From 75673ae96d0da5149bb46bfd1d54e2acf4678049 Mon Sep 17 00:00:00 2001 From: harshithnrao Date: Sun, 6 Apr 2025 17:55:09 +0530 Subject: [PATCH] minor bug fixes and validation dtos --- package-lock.json | 108 ++++++++++++++-- package.json | 5 +- src/app-config/config.json | 23 ++-- src/app-config/config.local.json | 23 ++-- src/auth/auth.controller.ts | 21 ++- src/auth/auth.service.ts | 30 +++-- src/booking-gateway/booking.gateway.ts | 2 +- src/common/files.service.ts | 63 +++++++++ src/event/event.controller.ts | 44 ++++++- src/event/event.dto.ts | 120 ++++++++++++++++++ .../eventAdditionalDetail.dto.ts | 66 ++++++++++ src/google-oauth/google.strategy.ts | 2 +- src/payout/payout.controller.ts | 21 +-- src/payout/payout.dto.ts | 88 +++++++++++++ src/payout/payout.service.ts | 7 +- .../push-subscription.controller.ts | 4 +- .../push-subscription.service.ts | 27 ++-- src/redis/redis.controller.ts | 60 ++++++--- src/redis/redis.module.ts | 2 +- src/redis/redis.service.ts | 4 +- src/refund/refund.dto.ts | 83 ++++++++++++ src/review/review.dto.ts | 79 ++++++++++++ src/seat/seat.controller.ts | 10 +- src/seat/seat.dto.ts | 84 ++++++++++++ src/seat/seat.module.ts | 6 +- src/seat/seat.service.ts | 2 +- src/theatre/theatre.dto.ts | 94 ++++++++++++++ .../theatreAdditionalDetails.dto.ts | 74 +++++++++++ src/ticket/ticket.dto.ts | 110 ++++++++++++++++ src/ticketPricing/ticketPricing.dto.ts | 76 +++++++++++ src/timeSlot/timeSlot.dto.ts | 76 +++++++++++ src/user/user.dto.ts | 90 +++++++++++++ src/user/user.service.ts | 2 +- 33 files changed, 1402 insertions(+), 104 deletions(-) create mode 100644 src/common/files.service.ts create mode 100644 src/event/event.dto.ts create mode 100644 src/event/eventAdditionalDetail/eventAdditionalDetail.dto.ts create mode 100644 src/payout/payout.dto.ts create mode 100644 src/refund/refund.dto.ts create mode 100644 src/review/review.dto.ts create mode 100644 src/seat/seat.dto.ts create mode 100644 src/theatre/theatre.dto.ts create mode 100644 src/theatre/theatreAdditionalDetails/theatreAdditionalDetails.dto.ts create mode 100644 src/ticket/ticket.dto.ts create mode 100644 src/ticketPricing/ticketPricing.dto.ts create mode 100644 src/timeSlot/timeSlot.dto.ts create mode 100644 src/user/user.dto.ts diff --git a/package-lock.json b/package-lock.json index 80e7bca..0888424 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,15 +15,18 @@ "@nestjs/core": "^10.4.15", "@nestjs/jwt": "^11.0.0", "@nestjs/passport": "^11.0.5", - "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-express": "^10.4.15", "@nestjs/platform-socket.io": "^10.4.15", "@nestjs/swagger": "^8.1.1", "@nestjs/typeorm": "^10.0.1", "@nestjs/websockets": "^10.4.15", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", "dotenv": "^16.3.1", "handlebars": "^4.7.8", "ioredis": "^5.6.0", "moment": "^2.30.1", + "multer": "^1.4.5-lts.2", "nodemailer": "^6.9.9", "otp-generator": "^4.0.1", "passport": "^0.7.0", @@ -1918,6 +1921,24 @@ "@nestjs/core": "^10.0.0" } }, + "node_modules/@nestjs/platform-express/node_modules/multer": { + "version": "1.4.4-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", + "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/@nestjs/platform-socket.io": { "version": "10.4.15", "resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.4.15.tgz", @@ -2567,9 +2588,10 @@ } }, "node_modules/@types/validator": { - "version": "13.11.7", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", - "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" + "version": "13.12.3", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.3.tgz", + "integrity": "sha512-2ipwZ2NydGQJImne+FhNdhgRM37e9lCev99KnqkbFHd94Xn/mErARWI1RSLem1QA19ch5kOhzIZd7e8CA2FI8g==", + "license": "MIT" }, "node_modules/@types/yargs": { "version": "17.0.32", @@ -3806,6 +3828,23 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "license": "MIT" + }, + "node_modules/class-validator": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz", + "integrity": "sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==", + "license": "MIT", + "dependencies": { + "@types/validator": "^13.11.8", + "libphonenumber-js": "^1.10.53", + "validator": "^13.9.0" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -7050,6 +7089,12 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.12.6", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.6.tgz", + "integrity": "sha512-PJiS4ETaUfCOFLpmtKzAbqZQjCCKVu2OhTV4SVNNE7c2nu/dACvtCqj4L0i/KWNnIgRv7yrILvBj5Lonv5Ncxw==", + "license": "MIT" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -7409,9 +7454,10 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multer": { - "version": "1.4.4-lts.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", - "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", + "version": "1.4.5-lts.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", + "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", + "license": "MIT", "dependencies": { "append-field": "^1.0.0", "busboy": "^1.0.0", @@ -12086,6 +12132,22 @@ "express": "4.21.2", "multer": "1.4.4-lts.1", "tslib": "2.8.1" + }, + "dependencies": { + "multer": { + "version": "1.4.4-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", + "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + } } }, "@nestjs/platform-socket.io": { @@ -12626,9 +12688,9 @@ } }, "@types/validator": { - "version": "13.11.7", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", - "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" + "version": "13.12.3", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.3.tgz", + "integrity": "sha512-2ipwZ2NydGQJImne+FhNdhgRM37e9lCev99KnqkbFHd94Xn/mErARWI1RSLem1QA19ch5kOhzIZd7e8CA2FI8g==" }, "@types/yargs": { "version": "17.0.32", @@ -13485,6 +13547,21 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "class-validator": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz", + "integrity": "sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==", + "requires": { + "@types/validator": "^13.11.8", + "libphonenumber-js": "^1.10.53", + "validator": "^13.9.0" + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -15848,6 +15925,11 @@ "type-check": "~0.4.0" } }, + "libphonenumber-js": { + "version": "1.12.6", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.6.tgz", + "integrity": "sha512-PJiS4ETaUfCOFLpmtKzAbqZQjCCKVu2OhTV4SVNNE7c2nu/dACvtCqj4L0i/KWNnIgRv7yrILvBj5Lonv5Ncxw==" + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -16110,9 +16192,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multer": { - "version": "1.4.4-lts.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", - "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", + "version": "1.4.5-lts.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", + "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", "requires": { "append-field": "^1.0.0", "busboy": "^1.0.0", diff --git a/package.json b/package.json index 650667d..bfb98ad 100644 --- a/package.json +++ b/package.json @@ -29,15 +29,18 @@ "@nestjs/core": "^10.4.15", "@nestjs/jwt": "^11.0.0", "@nestjs/passport": "^11.0.5", - "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-express": "^10.4.15", "@nestjs/platform-socket.io": "^10.4.15", "@nestjs/swagger": "^8.1.1", "@nestjs/typeorm": "^10.0.1", "@nestjs/websockets": "^10.4.15", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", "dotenv": "^16.3.1", "handlebars": "^4.7.8", "ioredis": "^5.6.0", "moment": "^2.30.1", + "multer": "^1.4.5-lts.2", "nodemailer": "^6.9.9", "otp-generator": "^4.0.1", "passport": "^0.7.0", diff --git a/src/app-config/config.json b/src/app-config/config.json index c98a89f..9b35d49 100644 --- a/src/app-config/config.json +++ b/src/app-config/config.json @@ -53,19 +53,22 @@ }, "vapidConfig": { "email": "mailto:example@domain.com", - "publicKey": "BPcIQx6jQlD0m2WA5qzXnHtKtsBhvIf_aRf6foXx3ESiw2Tks6b8tVzzX3hHwerGtWy4togFEiJtk5X-Sq36uVQ", - "privateKey": "v-pRrypniFnPn6UOyDNIKatxoHCI6aqsXCM86L7aTfY" + "publicKey": "BJnRhhooOB7unX8yfpHXgbUVqR03A7zsAppguA7JfHMNmhgZ1-RqbA-y70neaPrtbfO8Q1GsipYIM05_SpLDUP0", + "privateKey": "7OAq3PXC3VCNPus6Mua9rxSO66Vd0j5J5Mv8g7hMbYc" }, - "redisConfig":{ - "host":"localhost", - "port":6379, - "db":0 + "redisConfig": { + "host": "localhost", + "port": 6379, + "db": 0 }, "googleOauthConfig": { - "clientId":"361418022886-4d4p2v7n9tq8t4tq8t4tq8tq8tq8tq8t.apps.googleusercontent.com", - "clientSecret":"GOCSPX-2Vt7b5Oo4t4t4t4t4t4t4t4t4t4", - "callbackURL":"http://localhost:3000/auth/google-redirect", - "scope":["email","profile"] + "clientId": "361418022886-q8inm4gh7aqhopitpsl87m0vcgces320.apps.googleusercontent.com", + "clientSecret": "GOCSPX-TwyERXKjx-8_U1X68ayJpCssfY", + "callbackURL": "http://localhost:3000/auth/google-redirect", + "scope": [ + "email", + "profile" + ] } } } \ No newline at end of file diff --git a/src/app-config/config.local.json b/src/app-config/config.local.json index c98a89f..9b35d49 100644 --- a/src/app-config/config.local.json +++ b/src/app-config/config.local.json @@ -53,19 +53,22 @@ }, "vapidConfig": { "email": "mailto:example@domain.com", - "publicKey": "BPcIQx6jQlD0m2WA5qzXnHtKtsBhvIf_aRf6foXx3ESiw2Tks6b8tVzzX3hHwerGtWy4togFEiJtk5X-Sq36uVQ", - "privateKey": "v-pRrypniFnPn6UOyDNIKatxoHCI6aqsXCM86L7aTfY" + "publicKey": "BJnRhhooOB7unX8yfpHXgbUVqR03A7zsAppguA7JfHMNmhgZ1-RqbA-y70neaPrtbfO8Q1GsipYIM05_SpLDUP0", + "privateKey": "7OAq3PXC3VCNPus6Mua9rxSO66Vd0j5J5Mv8g7hMbYc" }, - "redisConfig":{ - "host":"localhost", - "port":6379, - "db":0 + "redisConfig": { + "host": "localhost", + "port": 6379, + "db": 0 }, "googleOauthConfig": { - "clientId":"361418022886-4d4p2v7n9tq8t4tq8t4tq8tq8tq8tq8t.apps.googleusercontent.com", - "clientSecret":"GOCSPX-2Vt7b5Oo4t4t4t4t4t4t4t4t4t4", - "callbackURL":"http://localhost:3000/auth/google-redirect", - "scope":["email","profile"] + "clientId": "361418022886-q8inm4gh7aqhopitpsl87m0vcgces320.apps.googleusercontent.com", + "clientSecret": "GOCSPX-TwyERXKjx-8_U1X68ayJpCssfY", + "callbackURL": "http://localhost:3000/auth/google-redirect", + "scope": [ + "email", + "profile" + ] } } } \ No newline at end of file diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index d4da566..3b4146a 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -4,10 +4,12 @@ import { AuthService } from './auth.service'; import { Request, Response } from 'express'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { GoogleOauthGuard } from 'src/google-oauth/google-oauth.guard'; +import { User } from 'src/user/user.entity'; +import { UserService } from 'src/user/user.service'; @ApiTags('Auth') @Controller('auth') export class AuthController { - constructor(private authService: AuthService) { } + constructor(private authService: AuthService, private userService: UserService) { } @Post('login') @ApiOperation({ summary: 'Login' }) @@ -44,6 +46,23 @@ export class AuthController { res.status(200).send(httpResponse); } + @Post('signup') + async signup(@Body() userDto: User, @Res() res: Response) { + const user = await this.userService.findByEmail(userDto.email); + if (user) { + const errorResponse = new GenericResponse({ + exception: true, + exceptionSeverity: 'HIGH', + exceptionMessage: 'ERR.NOT_FOUND', + stackTrace: 'User already exists' + }, null); + res.status(404).send(errorResponse); + } + const userCreated = await this.userService.upsert(userDto, true); + const tokens = await this.authService.login(userCreated);//MARK: NEED MAILER TO SEND CONFIRMATION EMAIL + const httpResponse = new GenericResponse(null, tokens); + res.status(200).send(httpResponse); + } @Post('refresh') async refresh(@Body() body: { refresh_token: string }, @Res() res: Response) { const newToken = await this.authService.refreshAccessToken(body.refresh_token); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index ca8e817..9fb42cf 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -10,10 +10,10 @@ import { Request } from 'express'; @Injectable() export class AuthService { - + constructor(private userService: UserService, private jwtService: JwtService) { } - private async signToken(payload: any, type: 'accessToken' | 'refreshToken') { + private signToken(payload: any, type: 'accessToken' | 'refreshToken') { const config = Utility.jwtConfig[type]; return this.jwtService.sign(payload, { secret: config.secretOrKey, @@ -40,11 +40,19 @@ export class AuthService { async login(user: any) { const payload: JwtPayload = { email: user.email, password: user.password }; const accessToken = this.signToken(payload, 'accessToken'); - const refreshToken = this.signToken(payload, 'refreshToken'); - await RefreshToken.create({ email: user.email, token: refreshToken, type: 'jwt' }); + return { + access_token: accessToken, + refresh_token: refreshToken, + }; + } + async signup(user: any) { + const payload: JwtPayload = { email: user.email, password: user.password }; + const accessToken = this.signToken(payload, 'accessToken'); + const refreshToken = this.signToken(payload, 'refreshToken'); + await RefreshToken.create({ email: user.email, token: refreshToken, type: 'jwt' }); return { access_token: accessToken, refresh_token: refreshToken, @@ -95,22 +103,24 @@ export class AuthService { //google services async googleOauthRedirect(user) { - console.log("user in service is",user); - if(!user.email) { + console.log("user in service is", user); + if (!user.email) { return { statusCode: 400, message: 'User not found' } } - console.log("user.email in service is",user.email); + console.log("user.email in service is", user.email); let existingUser = await User.findOne({ where: { email: user.email } }); - if(!existingUser) { + if (!existingUser) { existingUser = await User.create({ email: user.email, - name: user.name,}); + name: user.name, + userTypeCode: 'user' + }); } - + const payload = existingUser.get(); const accessToken = await this.signToken(payload, 'accessToken'); const refreshToken = await this.signToken(payload, 'refreshToken'); diff --git a/src/booking-gateway/booking.gateway.ts b/src/booking-gateway/booking.gateway.ts index 0bfaa2f..581d47c 100644 --- a/src/booking-gateway/booking.gateway.ts +++ b/src/booking-gateway/booking.gateway.ts @@ -25,7 +25,7 @@ export class BookingGateway implements OnGatewayConnection, OnGatewayDisconnect this.server.emit('clientsUpdated', this.connectedClients); } - @SubscribeMessage('bookTciket') + @SubscribeMessage('bookTicket') async handleBookTicket(@MessageBody() ticket: Ticket) { const response = await this.bookingService.bookTicket(ticket); this.server.to(ticket.eventId.toString() ).emit('ticketBooked', response); diff --git a/src/common/files.service.ts b/src/common/files.service.ts new file mode 100644 index 0000000..02c9e73 --- /dev/null +++ b/src/common/files.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@nestjs/common'; +import { diskStorage } from 'multer'; +import { extname, join } from 'path'; +import * as fs from 'fs'; + +@Injectable() +export class FilesService { + // Method to configure Multer's storage + getMulterStorage() { + return diskStorage({ + destination: (req, file, cb) => { + // Define the upload path + const uploadPath = './uploads'; + + // Create the upload directory if it doesn't exist + if (!fs.existsSync(uploadPath)) { + fs.mkdirSync(uploadPath, { recursive: true }); + } + + // Set the destination directory for file storage + cb(null, uploadPath); + }, + filename: (req, file, cb) => { + // Generate a unique file name based on the current timestamp + const fileName = Date.now() + extname(file.originalname); + cb(null, fileName); + }, + }); + } + + // Method to filter file types based on MIME type and extension + fileFilter(req, file, cb) { + const allowedImageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg']; + const allowedVideoTypes = ['video/mp4', 'video/avi', 'video/mov']; + + // Check if the file is an image or a video + if (allowedImageTypes.includes(file.mimetype) || allowedVideoTypes.includes(file.mimetype)) { + return cb(null, true); // Allow the file + } else { + return cb(new Error('Only images (jpg, png, gif) and videos (mp4, avi, mov) are allowed!'), false); // Reject the file + } + } + + // Helper method to categorize the uploaded files into images and videos + categorizeFiles(files: Express.Multer.File[]): { image: string[]; video: string[] } { + const categorizedFiles = { + image: [], + video: [], + }; + + // Categorize files based on their extensions + files.forEach(file => { + const ext = extname(file.originalname).toLowerCase(); + if (['.jpg', '.jpeg', '.png', '.gif'].includes(ext)) { + categorizedFiles.image.push(file.path); // Categorize as image + } else if (['.mp4', '.avi', '.mov'].includes(ext)) { + categorizedFiles.video.push(file.path); // Categorize as video + } + }); + + return categorizedFiles; + } +} diff --git a/src/event/event.controller.ts b/src/event/event.controller.ts index 667fbc8..26b9427 100644 --- a/src/event/event.controller.ts +++ b/src/event/event.controller.ts @@ -1,14 +1,17 @@ -import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common'; +import { Body, Controller, Delete, Get, Param, Post, Put, Res, UploadedFile, UploadedFiles, UseInterceptors } from '@nestjs/common'; import { EventService } from './event.service'; import { Response } from 'express'; import { GenericResponse } from '../common/GenericResponse.model'; import Event from './event.entity'; import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger'; +import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express'; +import { diskStorage } from 'multer'; +import path from 'path'; @ApiTags('event') @Controller('event') export class EventController { - constructor(private eventService: EventService) {} + constructor(private eventService: EventService) { } @Get("/all") @ApiOperation({ summary: 'Get all events' }) @@ -31,7 +34,7 @@ export class EventController { }) async getAllEvents(@Res() res: Response) { const response = await this.eventService.findAll() || []; - if(!response) { + if (!response) { const errorResponse = new GenericResponse({ exception: true, exceptionSeverity: 'HIGH', @@ -178,8 +181,33 @@ export class EventController { status: 201, description: 'Successfully created a event', }) - async insert(@Body() event: Event, @Res() res: Response) { - if (!event) { + @UseInterceptors(FilesInterceptor('files', 10, { + storage: diskStorage({ + destination: './uploads', + filename: (req, file, callback) => { + console.log(file); + const filename = file.originalname; + callback(null, filename); + } + }) + })) + async insert(@Body() body: any, @Res() res: Response, @UploadedFiles() files?: Express.Multer.File[]) { + const event = JSON.parse(body.event) + console.log(event); + if (!files) { + console.log("No files"); + } + if (!event.orgEmail) { + const response = new GenericResponse({ + exception: true, + exceptionSeverity: 'HIGH', + exceptionMessage: 'ERR.MISSING_ORG_EMAIL', + stackTrace: 'Request' + }, null); + return res.status(400).send(response); + } + console.log(files); + if (!event || !files) { const response = new GenericResponse({ exception: true, exceptionSeverity: 'HIGH', @@ -188,6 +216,12 @@ export class EventController { }, null); return res.status(400).send(response); } + const imageFiles = files.filter(file => file.mimetype.startsWith('image/')).map(file => file.filename); + const videoFiles = files.filter(file => file.mimetype.startsWith('video/')).map(file => file.filename); + event.images = { + images: imageFiles, + videos: videoFiles, + }; delete event.id; const response = await this.eventService.upsert(event, true); const httpResponse = new GenericResponse(null, response); diff --git a/src/event/event.dto.ts b/src/event/event.dto.ts new file mode 100644 index 0000000..7448547 --- /dev/null +++ b/src/event/event.dto.ts @@ -0,0 +1,120 @@ +import { IsString, IsNumber, IsDate, IsOptional, IsEmail, IsArray, IsObject } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class EventDTO { + + @ApiProperty({ type: String }) + @IsEmail() + orgEmail: string; + + @ApiProperty({ type: String }) + @IsString() + eventName: string; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + startDate: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + endDate: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + theatreId: number; + + @ApiProperty({ type: String }) + @IsString() + eventTime: string; + + @ApiProperty({ type: String }) + @IsString() + chiefGuests: string; + + @ApiProperty({ type: String }) + @IsString() + description: string; + + @ApiProperty({ type: Object }) + @IsObject() + images: object; + + @ApiProperty({ type: String }) + @IsString() + categories: string; + + @ApiProperty({ type: Number }) + @IsNumber() + ageRestriction: number; + + @ApiProperty({ type: Number }) + @IsNumber() + purchaseLimit: number; + + @ApiProperty({ type: String }) + @IsString() + cast: string; + + @ApiProperty({ type: Number }) + @IsNumber() + maxSeating: number; + + @ApiProperty({ type: String }) + @IsString() + eventType: string; + + @ApiProperty({ type: String }) + @IsString() + promoted: string; + + @ApiProperty({ type: String }) + @IsString() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + version: number; +} + +export class EventUpdateDTO extends EventDTO { + @ApiProperty({ type: Number }) + @IsNumber() + id: number; +} diff --git a/src/event/eventAdditionalDetail/eventAdditionalDetail.dto.ts b/src/event/eventAdditionalDetail/eventAdditionalDetail.dto.ts new file mode 100644 index 0000000..e5feb7f --- /dev/null +++ b/src/event/eventAdditionalDetail/eventAdditionalDetail.dto.ts @@ -0,0 +1,66 @@ +import { IsString, IsNumber, IsDate, IsOptional, IsEmail, IsObject } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class EventAdditionalDetailDTO { + + @ApiProperty({ type: Number }) + @IsNumber() + eventsId: number; + + @ApiProperty({ type: String }) + @IsString() + addlDataType: string; + + @ApiProperty({ type: String }) + @IsString() + addlDataName: string; + + @ApiProperty({ type: String }) + @IsString() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + version: number; +} + +export class EventAdditionalDetailUpdateDTO extends EventAdditionalDetailDTO { + @ApiProperty({ type: Number }) + @IsNumber() + id: number; +} diff --git a/src/google-oauth/google.strategy.ts b/src/google-oauth/google.strategy.ts index 4533b4b..3b08420 100644 --- a/src/google-oauth/google.strategy.ts +++ b/src/google-oauth/google.strategy.ts @@ -10,7 +10,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') { super({ clientID: Utility.googleOauthConfig.clientId, clientSecret: Utility.googleOauthConfig.clientSecret, - callbackURL: Utility.googleOauthConfig.callbackUrl, + callbackURL: Utility.googleOauthConfig.callbackURL, scope: Utility.googleOauthConfig.scope, }); } diff --git a/src/payout/payout.controller.ts b/src/payout/payout.controller.ts index b33912e..67be855 100644 --- a/src/payout/payout.controller.ts +++ b/src/payout/payout.controller.ts @@ -1,14 +1,15 @@ -import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common'; +import { BadRequestException, Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common'; import { PayoutService } from './payout.service'; import { Response } from 'express'; import { GenericResponse } from '../common/GenericResponse.model'; import Payout from './payout.entity'; import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger'; +import { PayoutDTO, PayoutUpdateDTO } from './payout.dto'; @ApiTags('payout') @Controller('payout') export class PayoutController { - constructor(private payoutService: PayoutService) {} + constructor(private payoutService: PayoutService) { } @Get("/all") @ApiOperation({ summary: 'Get all payouts' }) @@ -30,8 +31,8 @@ export class PayoutController { } }) async getAllPayouts(@Res() res: Response) { - const response = await this.payoutService.findAll() || []; - if(!response) { + const response = await this.payoutService.findAll(); + if (!response) { const errorResponse = new GenericResponse({ exception: true, exceptionSeverity: 'HIGH', @@ -87,7 +88,7 @@ export class PayoutController { }, null); return res.status(400).send(response); } - const response = await this.payoutService.findByPk(id) || {}; + const response = await this.payoutService.findByPk(id); if (!response) { const errorResponse = new GenericResponse({ exception: true, @@ -178,17 +179,18 @@ export class PayoutController { status: 201, description: 'Successfully created a payout', }) - async insert(@Body() payout: Payout, @Res() res: Response) { + @UsePipes(new ValidationPipe({ whitelist: true })) + async insert(@Body() payout: PayoutDTO, @Res() res: Response) { + console.log("Received payout:", payout); if (!payout) { const response = new GenericResponse({ exception: true, exceptionSeverity: 'HIGH', exceptionMessage: 'ERR.INVALID_DATA', - stackTrace: 'Request' + stackTrace: 'Request body is invalid' }, null); return res.status(400).send(response); } - delete payout.id; const response = await this.payoutService.upsert(payout, true); const httpResponse = new GenericResponse(null, response); res.status(201).send(httpResponse); @@ -227,7 +229,8 @@ export class PayoutController { status: 200, description: 'Successfully updated payout', }) - async update(@Body() payout: Payout, @Res() res: Response) { + @UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true })) + async update(@Body() payout: PayoutUpdateDTO, @Res() res: Response) { if (!payout || !payout.id) { const response = new GenericResponse({ exception: true, diff --git a/src/payout/payout.dto.ts b/src/payout/payout.dto.ts new file mode 100644 index 0000000..ea79614 --- /dev/null +++ b/src/payout/payout.dto.ts @@ -0,0 +1,88 @@ +import { IsString, IsEmail, IsNumber, IsDate, IsOptional, IsNotEmpty, IsEnum } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class PayoutDTO { + + @ApiProperty({ type: String }) + @IsEmail() + @IsNotEmpty() + payeeEmail: string; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + amount: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + paymentMethod: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + transactionId: string; + + @ApiProperty({ type: String }) + @IsEmail() + @IsNotEmpty() + paidToEmail: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + payoutDate: Date; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class PayoutUpdateDTO extends PayoutDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number +} \ No newline at end of file diff --git a/src/payout/payout.service.ts b/src/payout/payout.service.ts index f657531..d794132 100644 --- a/src/payout/payout.service.ts +++ b/src/payout/payout.service.ts @@ -3,6 +3,7 @@ import Payout from './payout.entity'; import { firstValueFrom } from 'rxjs'; import { HttpService } from "@nestjs/axios"; import { Utility } from 'src/common/Utility'; +import { PayoutDTO, PayoutUpdateDTO } from './payout.dto'; @Injectable() export class PayoutService { @@ -32,16 +33,14 @@ export class PayoutService { return Payout.destroy({ where: { id: id } }); } - async upsert(payout: Payout, insertIfNotFound: boolean): Promise { + async upsert(payout: any, insertIfNotFound: boolean): Promise { if (payout.id) { const existingPayout = await this.findByPk(payout.id); if (existingPayout) { return Payout.update(payout, { where: { id: payout.id } }); } } - if (insertIfNotFound) { - //const textbookExists = await this.checkTextbookExists(payout.textbookId); - + if (insertIfNotFound) { return Payout.create(payout as any) } } diff --git a/src/push-subscription/push-subscription.controller.ts b/src/push-subscription/push-subscription.controller.ts index 4002f83..d910354 100644 --- a/src/push-subscription/push-subscription.controller.ts +++ b/src/push-subscription/push-subscription.controller.ts @@ -7,14 +7,14 @@ export class PushSubscriptionController { constructor(private readonly pushSubscriptionService: PushSubscriptionService) { } @Post('subscribe') - async subscribe(@Body() body: any) { + async subscribe(@Body() body: {endpoint: string, p256dh: string, auth: string}) { console.log(body); await this.pushSubscriptionService.saveSubscription(body); return 'subscribed'; } @Post('send-notification') - async sendNotification(@Body() body: any) { + async sendNotification(@Body() body: { title: string, message: string }) { await this.pushSubscriptionService.sendPushNotification(body.title, body.message); return 'notification sent'; } diff --git a/src/push-subscription/push-subscription.service.ts b/src/push-subscription/push-subscription.service.ts index 472ed6e..23dbbc5 100644 --- a/src/push-subscription/push-subscription.service.ts +++ b/src/push-subscription/push-subscription.service.ts @@ -1,6 +1,6 @@ import * as webPush from 'web-push'; import { Injectable } from '@nestjs/common'; -import PushSubscription from './push-subscription.entity'; +import PushSubscription from './push-subscription.entity'; import { Utility } from 'src/common/Utility'; @Injectable() @@ -19,25 +19,24 @@ export class PushSubscriptionService { return 'saved subscription'; } - async sendPushNotification(title: any, message: any) { - const subs = await PushSubscription.findAll(); - var pushSub: any; - for (const sub of subs) { - pushSub = { + async sendPushNotification(title: string, message: string) { + const subscriptions = await PushSubscription.findAll(); + const payload = JSON.stringify({ title, message }); + + for (const sub of subscriptions) { + const pushSub = { endpoint: sub.endpoint, keys: { p256dh: sub.p256dh, auth: sub.auth, }, }; - } - const payload = JSON.stringify({ title, message }) - - try { - await webPush.sendPushNotification(pushSub, payload) - } catch (err) { - console.log("error occurred", err) + try { + await webPush.sendNotification(pushSub, payload); + } catch (err) { + console.error('Error sending push notification', err); + } } } -} \ No newline at end of file +} diff --git a/src/redis/redis.controller.ts b/src/redis/redis.controller.ts index fa6a91f..9d872e8 100644 --- a/src/redis/redis.controller.ts +++ b/src/redis/redis.controller.ts @@ -1,36 +1,66 @@ import { Controller, Get, Param, Post, Body, Delete } from '@nestjs/common'; import { RedisService } from './redis.service'; +import { BadRequestException, InternalServerErrorException } from '@nestjs/common'; +import { Logger } from '@nestjs/common'; @Controller('redis') export class RedisController { - constructor(private readonly redisService: RedisService) { } + private readonly logger = new Logger(RedisController.name); + + constructor(private readonly redisService: RedisService) {} @Post('set') - async setValue(@Body() body: { key: string, value: string, ttl?: number }) { - if (body.ttl) { - await this.redisService.setTimed(body.key, body.value, body.ttl); + async setValue(@Body() body: { key: string; value: string; ttl?: number }) { + if (body.ttl && body.ttl <= 0) { + throw new BadRequestException('TTL must be a positive number'); } - else { - await this.redisService.set(body.key, body.value); + + try { + if (body.ttl) { + await this.redisService.setTimed(body.key, body.value, body.ttl); + } else { + await this.redisService.set(body.key, body.value); + } + return { success: true, message: 'Value set in Redis' }; + } catch (error) { + this.logger.error('Failed to set value in Redis', error.stack); + throw new InternalServerErrorException('Failed to set value in Redis'); } - return { message: 'Value set in Redis' }; } @Get('get/:key') async getValue(@Param('key') key: string) { - const value = await this.redisService.get(key); - return { value }; + try { + const value = await this.redisService.get(key); + if (value === null) { + throw new BadRequestException('Key not found'); + } + return { success: true, value }; + } catch (error) { + this.logger.error('Failed to get value from Redis', error.stack); + throw new InternalServerErrorException('Failed to get value from Redis'); + } } @Delete('del/:key') async deleteValue(@Param('key') key: string) { - await this.redisService.del(key); - return { message: 'Value deleted from Redis' }; + try { + await this.redisService.del(key); + return { success: true, message: 'Value deleted from Redis' }; + } catch (error) { + this.logger.error('Failed to delete value from Redis', error.stack); + throw new InternalServerErrorException('Failed to delete value from Redis'); + } } - @Delete('flushall') - async flushall() { - await this.redisService.flushall(); - return { message: 'Redis flushed' }; + @Get('flushall') + async flushAll() { + try { + await this.redisService.flushall(); + return { success: true, message: 'Redis flushed' }; + } catch (error) { + this.logger.error('Failed to flush Redis', error.stack); + throw new InternalServerErrorException('Failed to flush Redis'); + } } } diff --git a/src/redis/redis.module.ts b/src/redis/redis.module.ts index 4a10c52..37b84e9 100644 --- a/src/redis/redis.module.ts +++ b/src/redis/redis.module.ts @@ -6,6 +6,6 @@ import { RedisService } from './redis.service'; @Module({ controllers: [RedisController], providers: [RedisService, RedisProvider], - exports: [RedisProvider], + exports: [RedisProvider, RedisService], }) export class RedisModule { } diff --git a/src/redis/redis.service.ts b/src/redis/redis.service.ts index 19ec639..1a270a4 100644 --- a/src/redis/redis.service.ts +++ b/src/redis/redis.service.ts @@ -5,7 +5,7 @@ import { RedisProvider } from './redis.provider'; export class RedisService { constructor(private readonly redisProvider: RedisProvider) {} - async set(key: string, value: string): Promise { + async set(key: string, value: any): Promise { const client = this.redisProvider.client; await client.set(key, value, ); } @@ -20,7 +20,7 @@ export class RedisService { await client.flushall(); } - async setTimed(key: string, value: string, ttl: number): Promise { + async setTimed(key: string, value: any, ttl: number): Promise { const client = this.redisProvider.client; await client.set(key, value, 'EX', ttl); } diff --git a/src/refund/refund.dto.ts b/src/refund/refund.dto.ts new file mode 100644 index 0000000..67f6e5a --- /dev/null +++ b/src/refund/refund.dto.ts @@ -0,0 +1,83 @@ +import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty, IsEmail } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class RefundDTO { + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + ticketId: number; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + refundAmount: number; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + refundPercentage: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + refundReason: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + refundDate: Date; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class RefundUpdateDTO extends RefundDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number +} diff --git a/src/review/review.dto.ts b/src/review/review.dto.ts new file mode 100644 index 0000000..1d0b344 --- /dev/null +++ b/src/review/review.dto.ts @@ -0,0 +1,79 @@ +import { IsString, IsNumber, IsDate, IsNotEmpty, IsOptional, IsEmail } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class ReviewDTO { + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + eventId: number; + + @ApiProperty({ type: String }) + @IsEmail() + @IsNotEmpty() + buyerEmail: string; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + rating: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + comment: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class ReviewUpdateDTO extends ReviewDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number; +} diff --git a/src/seat/seat.controller.ts b/src/seat/seat.controller.ts index 432fd69..e0015f6 100644 --- a/src/seat/seat.controller.ts +++ b/src/seat/seat.controller.ts @@ -4,11 +4,12 @@ import { Response } from 'express'; import { GenericResponse } from '../common/GenericResponse.model'; import Seat from './seat.entity'; import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger'; +import { RedisService } from 'src/redis/redis.service'; @ApiTags('seat') @Controller('seat') export class SeatController { - constructor(private seatService: SeatService) {} + constructor(private seatService: SeatService, private redisService: RedisService) {} @Get("/all") @ApiOperation({ summary: 'Get all seats' }) @@ -30,7 +31,12 @@ export class SeatController { } }) async getAllSeats(@Res() res: Response) { - const response = await this.seatService.findAll() || []; + // const cacheKey = 'all_seats'; + // let response = await this.redisService.get(cacheKey); + // if (!response) { + const response = await this.seatService.findAll() || []; + // await this.redisService.setTimed(cacheKey, seats,300); + // } if(!response) { const errorResponse = new GenericResponse({ exception: true, diff --git a/src/seat/seat.dto.ts b/src/seat/seat.dto.ts new file mode 100644 index 0000000..892042d --- /dev/null +++ b/src/seat/seat.dto.ts @@ -0,0 +1,84 @@ +import { IsString, IsNumber, IsDate, IsNotEmpty, IsOptional } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class SeatDTO { + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + eventId: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + seatNumber: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + row: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + column: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + available: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class SeatUpdateDTO extends SeatDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number; +} diff --git a/src/seat/seat.module.ts b/src/seat/seat.module.ts index 78f6dcf..6f770f5 100644 --- a/src/seat/seat.module.ts +++ b/src/seat/seat.module.ts @@ -2,9 +2,13 @@ import { Module } from '@nestjs/common'; import { SeatController } from './seat.controller'; import { SeatService } from './seat.service'; import { HttpModule } from '@nestjs/axios'; +// import { RedisService } from 'src/redis/redis.service'; +// import { RedisProvider } from 'src/redis/redis.provider'; +// import Redis from 'ioredis'; +import { RedisModule } from 'src/redis/redis.module'; @Module({ - imports: [HttpModule], + imports: [HttpModule, RedisModule], providers: [SeatService], controllers: [SeatController], }) diff --git a/src/seat/seat.service.ts b/src/seat/seat.service.ts index 125bcb7..02f7be6 100644 --- a/src/seat/seat.service.ts +++ b/src/seat/seat.service.ts @@ -31,7 +31,7 @@ export class SeatService { } async bookSeat(eventId: number, seatNumber: string) { - return Seat.update({ awailable: 'booked' }, { where: { eventId: eventId, seatNumber: seatNumber } }); + return Seat.update({ available: 'booked' }, { where: { eventId: eventId, seatNumber: seatNumber } }); } async upsert(seat: Seat, insertIfNotFound: boolean): Promise { diff --git a/src/theatre/theatre.dto.ts b/src/theatre/theatre.dto.ts new file mode 100644 index 0000000..e69f97b --- /dev/null +++ b/src/theatre/theatre.dto.ts @@ -0,0 +1,94 @@ +import { IsString, IsNumber, IsDate, IsNotEmpty, IsOptional, IsObject } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class TheatreDTO { + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + theatreName: string; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + rows: number; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + columns: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + address: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + city: string; + + @ApiProperty({ type: Object }) + @IsObject() + @IsNotEmpty() + images: object; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + totalSeats: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class TheatreUpdateDTO extends TheatreDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number +} diff --git a/src/theatre/theatreAdditionalDetails/theatreAdditionalDetails.dto.ts b/src/theatre/theatreAdditionalDetails/theatreAdditionalDetails.dto.ts new file mode 100644 index 0000000..ee30527 --- /dev/null +++ b/src/theatre/theatreAdditionalDetails/theatreAdditionalDetails.dto.ts @@ -0,0 +1,74 @@ +import { IsString, IsNumber, IsDate, IsNotEmpty, IsOptional } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class TheatreAdditionalDetailsDTO { + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + theatreId: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + addlDataType: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + addlDataName: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class TheatreAdditionalDetailsUpdateDTO extends TheatreAdditionalDetailsDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number; +} diff --git a/src/ticket/ticket.dto.ts b/src/ticket/ticket.dto.ts new file mode 100644 index 0000000..9d86c43 --- /dev/null +++ b/src/ticket/ticket.dto.ts @@ -0,0 +1,110 @@ +import { IsString, IsNumber, IsDate, IsNotEmpty, IsEmail, IsOptional } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class TicketDTO { + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + eventId: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + ticketType: string; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + price: number; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + seatNumber: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + qrCode: string; + + @ApiProperty({ type: String }) + @IsEmail() + @IsNotEmpty() + buyerEmail: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + bookingDate: Date; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + paymentStatus: string; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + rescheduledAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + scanned: Date; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class TicketUpdateDTO extends TicketDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number +} diff --git a/src/ticketPricing/ticketPricing.dto.ts b/src/ticketPricing/ticketPricing.dto.ts new file mode 100644 index 0000000..f9cdff7 --- /dev/null +++ b/src/ticketPricing/ticketPricing.dto.ts @@ -0,0 +1,76 @@ +import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class TimeSlotDTO { + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + eventId: number; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + startTime: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + endTime: Date; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class TimeSlotUpdateDTO extends TimeSlotDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number +} diff --git a/src/timeSlot/timeSlot.dto.ts b/src/timeSlot/timeSlot.dto.ts new file mode 100644 index 0000000..f9cdff7 --- /dev/null +++ b/src/timeSlot/timeSlot.dto.ts @@ -0,0 +1,76 @@ +import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class TimeSlotDTO { + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + eventId: number; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + startTime: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + endTime: Date; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class TimeSlotUpdateDTO extends TimeSlotDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number +} diff --git a/src/user/user.dto.ts b/src/user/user.dto.ts new file mode 100644 index 0000000..70e9e05 --- /dev/null +++ b/src/user/user.dto.ts @@ -0,0 +1,90 @@ +import { IsString, IsEmail, IsOptional, IsNotEmpty, IsDate, IsNumber } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import UserAdditionalDetail from './user-additional-details/user-additional-details.entity'; + +export class UserDTO { + + @ApiProperty({ type: String }) + @IsEmail() + @IsNotEmpty() + email: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + password: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + userTypeCode: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + name: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + phoneNumber: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + primaryRole: string; + + @ApiProperty({ type: String }) + @IsString() + @IsNotEmpty() + status: string; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validFrom: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @IsNotEmpty() + @Transform(({ value }) => new Date(value)) + validTill: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + createdAt: Date; + + @ApiProperty({ type: Date }) + @IsDate() + @Transform(({ value }) => new Date(value)) + updatedAt: Date; + + @ApiProperty({ type: String }) + @IsString() + createdBy: string; + + @ApiProperty({ type: String }) + @IsString() + modifiedBy: string; + + @ApiProperty({ type: Date }) + @IsOptional() + @IsDate() + @Transform(({ value }) => value ? new Date(value) : null) + deletedAt: Date; + + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + version: number; +} + +export class UserUpdateDTO extends UserDTO { + @ApiProperty({ type: Number }) + @IsNumber() + @IsNotEmpty() + id: number +} diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 69f8180..14fce99 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -23,7 +23,7 @@ export class UserService { } filter(user: User) : Promise { - return User.findAll({where: user as any, include: UserAdditionalDetail}) + return User.findAll({where: user as any}) } async remove(id: number): Promise {