minor bug fixes and validation dtos

This commit is contained in:
harshithnrao 2025-04-06 17:55:09 +05:30
parent dab3b9dc61
commit 75673ae96d
33 changed files with 1402 additions and 104 deletions

108
package-lock.json generated
View File

@ -15,15 +15,18 @@
"@nestjs/core": "^10.4.15", "@nestjs/core": "^10.4.15",
"@nestjs/jwt": "^11.0.0", "@nestjs/jwt": "^11.0.0",
"@nestjs/passport": "^11.0.5", "@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/platform-socket.io": "^10.4.15",
"@nestjs/swagger": "^8.1.1", "@nestjs/swagger": "^8.1.1",
"@nestjs/typeorm": "^10.0.1", "@nestjs/typeorm": "^10.0.1",
"@nestjs/websockets": "^10.4.15", "@nestjs/websockets": "^10.4.15",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"ioredis": "^5.6.0", "ioredis": "^5.6.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"multer": "^1.4.5-lts.2",
"nodemailer": "^6.9.9", "nodemailer": "^6.9.9",
"otp-generator": "^4.0.1", "otp-generator": "^4.0.1",
"passport": "^0.7.0", "passport": "^0.7.0",
@ -1918,6 +1921,24 @@
"@nestjs/core": "^10.0.0" "@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": { "node_modules/@nestjs/platform-socket.io": {
"version": "10.4.15", "version": "10.4.15",
"resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.4.15.tgz", "resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.4.15.tgz",
@ -2567,9 +2588,10 @@
} }
}, },
"node_modules/@types/validator": { "node_modules/@types/validator": {
"version": "13.11.7", "version": "13.12.3",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.3.tgz",
"integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" "integrity": "sha512-2ipwZ2NydGQJImne+FhNdhgRM37e9lCev99KnqkbFHd94Xn/mErARWI1RSLem1QA19ch5kOhzIZd7e8CA2FI8g==",
"license": "MIT"
}, },
"node_modules/@types/yargs": { "node_modules/@types/yargs": {
"version": "17.0.32", "version": "17.0.32",
@ -3806,6 +3828,23 @@
"integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
"dev": true "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": { "node_modules/cli-cursor": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@ -7050,6 +7089,12 @@
"node": ">= 0.8.0" "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": { "node_modules/lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "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==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/multer": { "node_modules/multer": {
"version": "1.4.4-lts.1", "version": "1.4.5-lts.2",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz",
"integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==",
"license": "MIT",
"dependencies": { "dependencies": {
"append-field": "^1.0.0", "append-field": "^1.0.0",
"busboy": "^1.0.0", "busboy": "^1.0.0",
@ -12086,6 +12132,22 @@
"express": "4.21.2", "express": "4.21.2",
"multer": "1.4.4-lts.1", "multer": "1.4.4-lts.1",
"tslib": "2.8.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": { "@nestjs/platform-socket.io": {
@ -12626,9 +12688,9 @@
} }
}, },
"@types/validator": { "@types/validator": {
"version": "13.11.7", "version": "13.12.3",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.3.tgz",
"integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" "integrity": "sha512-2ipwZ2NydGQJImne+FhNdhgRM37e9lCev99KnqkbFHd94Xn/mErARWI1RSLem1QA19ch5kOhzIZd7e8CA2FI8g=="
}, },
"@types/yargs": { "@types/yargs": {
"version": "17.0.32", "version": "17.0.32",
@ -13485,6 +13547,21 @@
"integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
"dev": true "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": { "cli-cursor": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@ -15848,6 +15925,11 @@
"type-check": "~0.4.0" "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": { "lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "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==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"multer": { "multer": {
"version": "1.4.4-lts.1", "version": "1.4.5-lts.2",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz",
"integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==",
"requires": { "requires": {
"append-field": "^1.0.0", "append-field": "^1.0.0",
"busboy": "^1.0.0", "busboy": "^1.0.0",

View File

@ -29,15 +29,18 @@
"@nestjs/core": "^10.4.15", "@nestjs/core": "^10.4.15",
"@nestjs/jwt": "^11.0.0", "@nestjs/jwt": "^11.0.0",
"@nestjs/passport": "^11.0.5", "@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/platform-socket.io": "^10.4.15",
"@nestjs/swagger": "^8.1.1", "@nestjs/swagger": "^8.1.1",
"@nestjs/typeorm": "^10.0.1", "@nestjs/typeorm": "^10.0.1",
"@nestjs/websockets": "^10.4.15", "@nestjs/websockets": "^10.4.15",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"ioredis": "^5.6.0", "ioredis": "^5.6.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"multer": "^1.4.5-lts.2",
"nodemailer": "^6.9.9", "nodemailer": "^6.9.9",
"otp-generator": "^4.0.1", "otp-generator": "^4.0.1",
"passport": "^0.7.0", "passport": "^0.7.0",

View File

@ -53,19 +53,22 @@
}, },
"vapidConfig": { "vapidConfig": {
"email": "mailto:example@domain.com", "email": "mailto:example@domain.com",
"publicKey": "BPcIQx6jQlD0m2WA5qzXnHtKtsBhvIf_aRf6foXx3ESiw2Tks6b8tVzzX3hHwerGtWy4togFEiJtk5X-Sq36uVQ", "publicKey": "BJnRhhooOB7unX8yfpHXgbUVqR03A7zsAppguA7JfHMNmhgZ1-RqbA-y70neaPrtbfO8Q1GsipYIM05_SpLDUP0",
"privateKey": "v-pRrypniFnPn6UOyDNIKatxoHCI6aqsXCM86L7aTfY" "privateKey": "7OAq3PXC3VCNPus6Mua9rxSO66Vd0j5J5Mv8g7hMbYc"
}, },
"redisConfig":{ "redisConfig": {
"host":"localhost", "host": "localhost",
"port":6379, "port": 6379,
"db":0 "db": 0
}, },
"googleOauthConfig": { "googleOauthConfig": {
"clientId":"361418022886-4d4p2v7n9tq8t4tq8t4tq8tq8tq8tq8t.apps.googleusercontent.com", "clientId": "361418022886-q8inm4gh7aqhopitpsl87m0vcgces320.apps.googleusercontent.com",
"clientSecret":"GOCSPX-2Vt7b5Oo4t4t4t4t4t4t4t4t4t4", "clientSecret": "GOCSPX-TwyERXKjx-8_U1X68ayJpCssfY",
"callbackURL":"http://localhost:3000/auth/google-redirect", "callbackURL": "http://localhost:3000/auth/google-redirect",
"scope":["email","profile"] "scope": [
"email",
"profile"
]
} }
} }
} }

View File

@ -53,19 +53,22 @@
}, },
"vapidConfig": { "vapidConfig": {
"email": "mailto:example@domain.com", "email": "mailto:example@domain.com",
"publicKey": "BPcIQx6jQlD0m2WA5qzXnHtKtsBhvIf_aRf6foXx3ESiw2Tks6b8tVzzX3hHwerGtWy4togFEiJtk5X-Sq36uVQ", "publicKey": "BJnRhhooOB7unX8yfpHXgbUVqR03A7zsAppguA7JfHMNmhgZ1-RqbA-y70neaPrtbfO8Q1GsipYIM05_SpLDUP0",
"privateKey": "v-pRrypniFnPn6UOyDNIKatxoHCI6aqsXCM86L7aTfY" "privateKey": "7OAq3PXC3VCNPus6Mua9rxSO66Vd0j5J5Mv8g7hMbYc"
}, },
"redisConfig":{ "redisConfig": {
"host":"localhost", "host": "localhost",
"port":6379, "port": 6379,
"db":0 "db": 0
}, },
"googleOauthConfig": { "googleOauthConfig": {
"clientId":"361418022886-4d4p2v7n9tq8t4tq8t4tq8tq8tq8tq8t.apps.googleusercontent.com", "clientId": "361418022886-q8inm4gh7aqhopitpsl87m0vcgces320.apps.googleusercontent.com",
"clientSecret":"GOCSPX-2Vt7b5Oo4t4t4t4t4t4t4t4t4t4", "clientSecret": "GOCSPX-TwyERXKjx-8_U1X68ayJpCssfY",
"callbackURL":"http://localhost:3000/auth/google-redirect", "callbackURL": "http://localhost:3000/auth/google-redirect",
"scope":["email","profile"] "scope": [
"email",
"profile"
]
} }
} }
} }

View File

@ -4,10 +4,12 @@ import { AuthService } from './auth.service';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { GoogleOauthGuard } from 'src/google-oauth/google-oauth.guard'; 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') @ApiTags('Auth')
@Controller('auth') @Controller('auth')
export class AuthController { export class AuthController {
constructor(private authService: AuthService) { } constructor(private authService: AuthService, private userService: UserService) { }
@Post('login') @Post('login')
@ApiOperation({ summary: 'Login' }) @ApiOperation({ summary: 'Login' })
@ -44,6 +46,23 @@ export class AuthController {
res.status(200).send(httpResponse); 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') @Post('refresh')
async refresh(@Body() body: { refresh_token: string }, @Res() res: Response) { async refresh(@Body() body: { refresh_token: string }, @Res() res: Response) {
const newToken = await this.authService.refreshAccessToken(body.refresh_token); const newToken = await this.authService.refreshAccessToken(body.refresh_token);

View File

@ -13,7 +13,7 @@ export class AuthService {
constructor(private userService: UserService, private jwtService: JwtService) { } 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]; const config = Utility.jwtConfig[type];
return this.jwtService.sign(payload, { return this.jwtService.sign(payload, {
secret: config.secretOrKey, secret: config.secretOrKey,
@ -40,11 +40,19 @@ export class AuthService {
async login(user: any) { async login(user: any) {
const payload: JwtPayload = { email: user.email, password: user.password }; const payload: JwtPayload = { email: user.email, password: user.password };
const accessToken = this.signToken(payload, 'accessToken'); const accessToken = this.signToken(payload, 'accessToken');
const refreshToken = this.signToken(payload, 'refreshToken'); const refreshToken = this.signToken(payload, 'refreshToken');
await RefreshToken.create({ email: user.email, token: refreshToken, type: 'jwt' }); 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 { return {
access_token: accessToken, access_token: accessToken,
refresh_token: refreshToken, refresh_token: refreshToken,
@ -95,19 +103,21 @@ export class AuthService {
//google services //google services
async googleOauthRedirect(user) { async googleOauthRedirect(user) {
console.log("user in service is",user); console.log("user in service is", user);
if(!user.email) { if (!user.email) {
return { return {
statusCode: 400, statusCode: 400,
message: 'User not found' 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 } }); let existingUser = await User.findOne({ where: { email: user.email } });
if(!existingUser) { if (!existingUser) {
existingUser = await User.create({ existingUser = await User.create({
email: user.email, email: user.email,
name: user.name,}); name: user.name,
userTypeCode: 'user'
});
} }

View File

@ -25,7 +25,7 @@ export class BookingGateway implements OnGatewayConnection, OnGatewayDisconnect
this.server.emit('clientsUpdated', this.connectedClients); this.server.emit('clientsUpdated', this.connectedClients);
} }
@SubscribeMessage('bookTciket') @SubscribeMessage('bookTicket')
async handleBookTicket(@MessageBody() ticket: Ticket) { async handleBookTicket(@MessageBody() ticket: Ticket) {
const response = await this.bookingService.bookTicket(ticket); const response = await this.bookingService.bookTicket(ticket);
this.server.to(ticket.eventId.toString() ).emit('ticketBooked', response); this.server.to(ticket.eventId.toString() ).emit('ticketBooked', response);

View File

@ -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;
}
}

View File

@ -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 { EventService } from './event.service';
import { Response } from 'express'; import { Response } from 'express';
import { GenericResponse } from '../common/GenericResponse.model'; import { GenericResponse } from '../common/GenericResponse.model';
import Event from './event.entity'; import Event from './event.entity';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger'; 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') @ApiTags('event')
@Controller('event') @Controller('event')
export class EventController { export class EventController {
constructor(private eventService: EventService) {} constructor(private eventService: EventService) { }
@Get("/all") @Get("/all")
@ApiOperation({ summary: 'Get all events' }) @ApiOperation({ summary: 'Get all events' })
@ -31,7 +34,7 @@ export class EventController {
}) })
async getAllEvents(@Res() res: Response) { async getAllEvents(@Res() res: Response) {
const response = await this.eventService.findAll() || []; const response = await this.eventService.findAll() || [];
if(!response) { if (!response) {
const errorResponse = new GenericResponse({ const errorResponse = new GenericResponse({
exception: true, exception: true,
exceptionSeverity: 'HIGH', exceptionSeverity: 'HIGH',
@ -178,8 +181,33 @@ export class EventController {
status: 201, status: 201,
description: 'Successfully created a event', description: 'Successfully created a event',
}) })
async insert(@Body() event: Event, @Res() res: Response) { @UseInterceptors(FilesInterceptor('files', 10, {
if (!event) { 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({ const response = new GenericResponse({
exception: true, exception: true,
exceptionSeverity: 'HIGH', exceptionSeverity: 'HIGH',
@ -188,6 +216,12 @@ export class EventController {
}, null); }, null);
return res.status(400).send(response); 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; delete event.id;
const response = await this.eventService.upsert(event, true); const response = await this.eventService.upsert(event, true);
const httpResponse = new GenericResponse(null, response); const httpResponse = new GenericResponse(null, response);

120
src/event/event.dto.ts Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -10,7 +10,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
super({ super({
clientID: Utility.googleOauthConfig.clientId, clientID: Utility.googleOauthConfig.clientId,
clientSecret: Utility.googleOauthConfig.clientSecret, clientSecret: Utility.googleOauthConfig.clientSecret,
callbackURL: Utility.googleOauthConfig.callbackUrl, callbackURL: Utility.googleOauthConfig.callbackURL,
scope: Utility.googleOauthConfig.scope, scope: Utility.googleOauthConfig.scope,
}); });
} }

View File

@ -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 { PayoutService } from './payout.service';
import { Response } from 'express'; import { Response } from 'express';
import { GenericResponse } from '../common/GenericResponse.model'; import { GenericResponse } from '../common/GenericResponse.model';
import Payout from './payout.entity'; import Payout from './payout.entity';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
import { PayoutDTO, PayoutUpdateDTO } from './payout.dto';
@ApiTags('payout') @ApiTags('payout')
@Controller('payout') @Controller('payout')
export class PayoutController { export class PayoutController {
constructor(private payoutService: PayoutService) {} constructor(private payoutService: PayoutService) { }
@Get("/all") @Get("/all")
@ApiOperation({ summary: 'Get all payouts' }) @ApiOperation({ summary: 'Get all payouts' })
@ -30,8 +31,8 @@ export class PayoutController {
} }
}) })
async getAllPayouts(@Res() res: Response) { async getAllPayouts(@Res() res: Response) {
const response = await this.payoutService.findAll() || []; const response = await this.payoutService.findAll();
if(!response) { if (!response) {
const errorResponse = new GenericResponse({ const errorResponse = new GenericResponse({
exception: true, exception: true,
exceptionSeverity: 'HIGH', exceptionSeverity: 'HIGH',
@ -87,7 +88,7 @@ export class PayoutController {
}, null); }, null);
return res.status(400).send(response); return res.status(400).send(response);
} }
const response = await this.payoutService.findByPk(id) || {}; const response = await this.payoutService.findByPk(id);
if (!response) { if (!response) {
const errorResponse = new GenericResponse({ const errorResponse = new GenericResponse({
exception: true, exception: true,
@ -178,17 +179,18 @@ export class PayoutController {
status: 201, status: 201,
description: 'Successfully created a payout', 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) { if (!payout) {
const response = new GenericResponse({ const response = new GenericResponse({
exception: true, exception: true,
exceptionSeverity: 'HIGH', exceptionSeverity: 'HIGH',
exceptionMessage: 'ERR.INVALID_DATA', exceptionMessage: 'ERR.INVALID_DATA',
stackTrace: 'Request' stackTrace: 'Request body is invalid'
}, null); }, null);
return res.status(400).send(response); return res.status(400).send(response);
} }
delete payout.id;
const response = await this.payoutService.upsert(payout, true); const response = await this.payoutService.upsert(payout, true);
const httpResponse = new GenericResponse(null, response); const httpResponse = new GenericResponse(null, response);
res.status(201).send(httpResponse); res.status(201).send(httpResponse);
@ -227,7 +229,8 @@ export class PayoutController {
status: 200, status: 200,
description: 'Successfully updated payout', 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) { if (!payout || !payout.id) {
const response = new GenericResponse({ const response = new GenericResponse({
exception: true, exception: true,

88
src/payout/payout.dto.ts Normal file
View File

@ -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
}

View File

@ -3,6 +3,7 @@ import Payout from './payout.entity';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { HttpService } from "@nestjs/axios"; import { HttpService } from "@nestjs/axios";
import { Utility } from 'src/common/Utility'; import { Utility } from 'src/common/Utility';
import { PayoutDTO, PayoutUpdateDTO } from './payout.dto';
@Injectable() @Injectable()
export class PayoutService { export class PayoutService {
@ -32,7 +33,7 @@ export class PayoutService {
return Payout.destroy({ where: { id: id } }); return Payout.destroy({ where: { id: id } });
} }
async upsert(payout: Payout, insertIfNotFound: boolean): Promise<Payout | [affectedCount: number]> { async upsert(payout: any, insertIfNotFound: boolean): Promise<Payout | [affectedCount: number]> {
if (payout.id) { if (payout.id) {
const existingPayout = await this.findByPk(payout.id); const existingPayout = await this.findByPk(payout.id);
if (existingPayout) { if (existingPayout) {
@ -40,8 +41,6 @@ export class PayoutService {
} }
} }
if (insertIfNotFound) { if (insertIfNotFound) {
//const textbookExists = await this.checkTextbookExists(payout.textbookId);
return Payout.create(payout as any) return Payout.create(payout as any)
} }
} }

View File

@ -7,14 +7,14 @@ export class PushSubscriptionController {
constructor(private readonly pushSubscriptionService: PushSubscriptionService) { } constructor(private readonly pushSubscriptionService: PushSubscriptionService) { }
@Post('subscribe') @Post('subscribe')
async subscribe(@Body() body: any) { async subscribe(@Body() body: {endpoint: string, p256dh: string, auth: string}) {
console.log(body); console.log(body);
await this.pushSubscriptionService.saveSubscription(body); await this.pushSubscriptionService.saveSubscription(body);
return 'subscribed'; return 'subscribed';
} }
@Post('send-notification') @Post('send-notification')
async sendNotification(@Body() body: any) { async sendNotification(@Body() body: { title: string, message: string }) {
await this.pushSubscriptionService.sendPushNotification(body.title, body.message); await this.pushSubscriptionService.sendPushNotification(body.title, body.message);
return 'notification sent'; return 'notification sent';
} }

View File

@ -19,25 +19,24 @@ export class PushSubscriptionService {
return 'saved subscription'; return 'saved subscription';
} }
async sendPushNotification(title: any, message: any) { async sendPushNotification(title: string, message: string) {
const subs = await PushSubscription.findAll(); const subscriptions = await PushSubscription.findAll();
var pushSub: any; const payload = JSON.stringify({ title, message });
for (const sub of subs) {
pushSub = { for (const sub of subscriptions) {
const pushSub = {
endpoint: sub.endpoint, endpoint: sub.endpoint,
keys: { keys: {
p256dh: sub.p256dh, p256dh: sub.p256dh,
auth: sub.auth, auth: sub.auth,
}, },
}; };
}
const payload = JSON.stringify({ title, message })
try { try {
await webPush.sendPushNotification(pushSub, payload) await webPush.sendNotification(pushSub, payload);
} catch (err) { } catch (err) {
console.log("error occurred", err) console.error('Error sending push notification', err);
}
} }
} }
} }

View File

@ -1,36 +1,66 @@
import { Controller, Get, Param, Post, Body, Delete } from '@nestjs/common'; import { Controller, Get, Param, Post, Body, Delete } from '@nestjs/common';
import { RedisService } from './redis.service'; import { RedisService } from './redis.service';
import { BadRequestException, InternalServerErrorException } from '@nestjs/common';
import { Logger } from '@nestjs/common';
@Controller('redis') @Controller('redis')
export class RedisController { export class RedisController {
constructor(private readonly redisService: RedisService) { } private readonly logger = new Logger(RedisController.name);
constructor(private readonly redisService: RedisService) {}
@Post('set') @Post('set')
async setValue(@Body() body: { key: string, value: string, ttl?: number }) { 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');
}
try {
if (body.ttl) { if (body.ttl) {
await this.redisService.setTimed(body.key, body.value, body.ttl); await this.redisService.setTimed(body.key, body.value, body.ttl);
} } else {
else {
await this.redisService.set(body.key, body.value); await this.redisService.set(body.key, body.value);
} }
return { message: 'Value set in Redis' }; 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');
}
} }
@Get('get/:key') @Get('get/:key')
async getValue(@Param('key') key: string) { async getValue(@Param('key') key: string) {
try {
const value = await this.redisService.get(key); const value = await this.redisService.get(key);
return { value }; 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') @Delete('del/:key')
async deleteValue(@Param('key') key: string) { async deleteValue(@Param('key') key: string) {
try {
await this.redisService.del(key); await this.redisService.del(key);
return { message: 'Value deleted from Redis' }; 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') @Get('flushall')
async flushall() { async flushAll() {
try {
await this.redisService.flushall(); await this.redisService.flushall();
return { message: 'Redis flushed' }; return { success: true, message: 'Redis flushed' };
} catch (error) {
this.logger.error('Failed to flush Redis', error.stack);
throw new InternalServerErrorException('Failed to flush Redis');
}
} }
} }

View File

@ -6,6 +6,6 @@ import { RedisService } from './redis.service';
@Module({ @Module({
controllers: [RedisController], controllers: [RedisController],
providers: [RedisService, RedisProvider], providers: [RedisService, RedisProvider],
exports: [RedisProvider], exports: [RedisProvider, RedisService],
}) })
export class RedisModule { } export class RedisModule { }

View File

@ -5,7 +5,7 @@ import { RedisProvider } from './redis.provider';
export class RedisService { export class RedisService {
constructor(private readonly redisProvider: RedisProvider) {} constructor(private readonly redisProvider: RedisProvider) {}
async set(key: string, value: string): Promise<void> { async set(key: string, value: any): Promise<void> {
const client = this.redisProvider.client; const client = this.redisProvider.client;
await client.set(key, value, ); await client.set(key, value, );
} }
@ -20,7 +20,7 @@ export class RedisService {
await client.flushall(); await client.flushall();
} }
async setTimed(key: string, value: string, ttl: number): Promise<void> { async setTimed(key: string, value: any, ttl: number): Promise<void> {
const client = this.redisProvider.client; const client = this.redisProvider.client;
await client.set(key, value, 'EX', ttl); await client.set(key, value, 'EX', ttl);
} }

83
src/refund/refund.dto.ts Normal file
View File

@ -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
}

79
src/review/review.dto.ts Normal file
View File

@ -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;
}

View File

@ -4,11 +4,12 @@ import { Response } from 'express';
import { GenericResponse } from '../common/GenericResponse.model'; import { GenericResponse } from '../common/GenericResponse.model';
import Seat from './seat.entity'; import Seat from './seat.entity';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
import { RedisService } from 'src/redis/redis.service';
@ApiTags('seat') @ApiTags('seat')
@Controller('seat') @Controller('seat')
export class SeatController { export class SeatController {
constructor(private seatService: SeatService) {} constructor(private seatService: SeatService, private redisService: RedisService) {}
@Get("/all") @Get("/all")
@ApiOperation({ summary: 'Get all seats' }) @ApiOperation({ summary: 'Get all seats' })
@ -30,7 +31,12 @@ export class SeatController {
} }
}) })
async getAllSeats(@Res() res: Response) { async getAllSeats(@Res() res: Response) {
// const cacheKey = 'all_seats';
// let response = await this.redisService.get(cacheKey);
// if (!response) {
const response = await this.seatService.findAll() || []; const response = await this.seatService.findAll() || [];
// await this.redisService.setTimed(cacheKey, seats,300);
// }
if(!response) { if(!response) {
const errorResponse = new GenericResponse({ const errorResponse = new GenericResponse({
exception: true, exception: true,

84
src/seat/seat.dto.ts Normal file
View File

@ -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;
}

View File

@ -2,9 +2,13 @@ import { Module } from '@nestjs/common';
import { SeatController } from './seat.controller'; import { SeatController } from './seat.controller';
import { SeatService } from './seat.service'; import { SeatService } from './seat.service';
import { HttpModule } from '@nestjs/axios'; 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({ @Module({
imports: [HttpModule], imports: [HttpModule, RedisModule],
providers: [SeatService], providers: [SeatService],
controllers: [SeatController], controllers: [SeatController],
}) })

View File

@ -31,7 +31,7 @@ export class SeatService {
} }
async bookSeat(eventId: number, seatNumber: string) { 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<Seat | [affectedCount: number]> { async upsert(seat: Seat, insertIfNotFound: boolean): Promise<Seat | [affectedCount: number]> {

View File

@ -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
}

View File

@ -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;
}

110
src/ticket/ticket.dto.ts Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

90
src/user/user.dto.ts Normal file
View File

@ -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
}

View File

@ -23,7 +23,7 @@ export class UserService {
} }
filter(user: User) : Promise<User[]> { filter(user: User) : Promise<User[]> {
return User.findAll({where: user as any, include: UserAdditionalDetail}) return User.findAll({where: user as any})
} }
async remove(id: number): Promise<number> { async remove(id: number): Promise<number> {