Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 81ff748795 | |||
| 1b7e5569bc | |||
| b9f3210bc4 | |||
| f5290a59c3 | |||
| 26465e1a46 | |||
| 3185762359 | |||
| c19866f960 | |||
| 39097d2ecb | |||
| 86ab856b1d | |||
| 3e55616599 | |||
| 8cd523aaff | |||
| be1ffc6aec | |||
| 1c35cc6116 | |||
| 381a806792 | |||
| 2d988ea5b5 | |||
| 90ca9ec298 | |||
| 49be465b01 | |||
| 929358e6d9 | |||
| c37f6167f8 | |||
| 619b97ff92 | |||
|
|
159f8a0988 | ||
|
|
5c24732ae4 | ||
|
|
0fceef8c44 | ||
|
|
90f378a877 | ||
|
|
75673ae96d | ||
|
|
dab3b9dc61 | ||
|
|
a293cdc04c | ||
|
|
7c3fdd2fda |
8
.env
8
.env
@ -1,8 +1,8 @@
|
||||
POSTGRES_HOST=127.0.0.1
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_HOST=192.168.0.113
|
||||
POSTGRES_PORT=5431
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_PASSWORD=FAdDoCwhmi3BvkK4pgEGDc7EspmDtHYV4y93748Xz6VysJKPdlsaU3L9N9k7OD9t
|
||||
POSTGRES_DATABASE=wastecare
|
||||
PORT=3000
|
||||
MODE=DEV
|
||||
RUN_MIGRATIONS=false
|
||||
RUN_MIGRATIONS=true
|
||||
@ -93,7 +93,6 @@ CREATE TABLE "rules_details_ref" (
|
||||
"deletedAt" DATE,
|
||||
"version" NUMERIC
|
||||
);
|
||||
|
||||
CREATE TABLE "users" (
|
||||
"id" BIGSERIAL PRIMARY KEY NOT NULL,
|
||||
"email" TEXT UNIQUE NOT NULL,
|
||||
@ -102,6 +101,8 @@ CREATE TABLE "users" (
|
||||
"name" TEXT,
|
||||
"phoneNumber" TEXT,
|
||||
"primaryRole" TEXT,
|
||||
"resetCode" TEXT,
|
||||
"resetCodeExpires" TIMESTAMP,
|
||||
"status" TEXT,
|
||||
"validFrom" DATE,
|
||||
"validTill" DATE,
|
||||
@ -183,7 +184,7 @@ CREATE TABLE "theatre_additional_details" (
|
||||
|
||||
CREATE TABLE "events" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"org_email" TEXT NOT NULL,
|
||||
"organizer_id" TEXT NOT NULL,
|
||||
"event_name" TEXT,
|
||||
"start_date" DATE,
|
||||
"end_date" DATE,
|
||||
@ -280,7 +281,7 @@ CREATE TABLE "tickets" (
|
||||
"price" NUMERIC,
|
||||
"seat_number" TEXT,
|
||||
"qr_code" TEXT,
|
||||
"buyer_email" TEXT NOT NULL,
|
||||
"buyer_id" NUMERIC NOT NULL,
|
||||
"booking_date" DATE,
|
||||
"payment_status" TEXT,
|
||||
"rescheduled_at" DATE,
|
||||
@ -299,7 +300,7 @@ CREATE TABLE "tickets" (
|
||||
CREATE TABLE "reviews" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"event_id" NUMERIC NOT NULL,
|
||||
"buyer_email" TEXT NOT NULL,
|
||||
"buyer_id" TEXT NOT NULL,
|
||||
"rating" NUMERIC,
|
||||
"comment" TEXT,
|
||||
"status" TEXT,
|
||||
@ -332,11 +333,11 @@ CREATE TABLE "seats" (
|
||||
|
||||
CREATE TABLE "payouts" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"payee_email" TEXT NOT NULL,
|
||||
"payee_id" TEXT NOT NULL,
|
||||
"amount" NUMERIC,
|
||||
"payment_method" TEXT,
|
||||
"transaction_id" TEXT,
|
||||
"paid_to_email" TEXT,
|
||||
"paid_to_id" TEXT,
|
||||
"payout_date" DATE,
|
||||
"status" TEXT,
|
||||
"validFrom" DATE,
|
||||
@ -369,6 +370,7 @@ CREATE TABLE "refunds" (
|
||||
|
||||
CREATE TABLE "push_notification" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"user_id" NUMERIC NOT NULL,
|
||||
"endpoint" TEXT NOT NULL,
|
||||
"p256dh" TEXT,
|
||||
"auth" TEXT,
|
||||
@ -382,3 +384,113 @@ CREATE TABLE "push_notification" (
|
||||
"deletedAt" DATE,
|
||||
"version" NUMERIC
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE "promotions" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"event_id" NUMERIC NOT NULL,
|
||||
"start_date" DATE,
|
||||
"end_date" DATE,
|
||||
"location" TEXT,
|
||||
"type" TEXT,
|
||||
"description" TEXT,
|
||||
"status" TEXT,
|
||||
"validFrom" DATE,
|
||||
"validTill" DATE,
|
||||
"createdAt" DATE,
|
||||
"updatedAt" DATE,
|
||||
"createdBy" TEXT,
|
||||
"modifiedBy" TEXT,
|
||||
"deletedAt" DATE,
|
||||
"version" NUMERIC
|
||||
);
|
||||
|
||||
CREATE TABLE "event_episodes" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"event_id" NUMERIC NOT NULL,
|
||||
"episode_name" TEXT,
|
||||
"episode_description" TEXT,
|
||||
"episode_start_date" DATE,
|
||||
"episode_end_date" DATE,
|
||||
"episode_location" TEXT,
|
||||
"episode_type" TEXT,
|
||||
"images" JSON,
|
||||
"status" TEXT,
|
||||
"validFrom" DATE,
|
||||
"validTill" DATE,
|
||||
"createdAt" DATE,
|
||||
"updatedAt" DATE,
|
||||
"createdBy" TEXT,
|
||||
"modifiedBy" TEXT,
|
||||
"deletedAt" DATE,
|
||||
"version" NUMERIC
|
||||
);
|
||||
|
||||
CREATE TABLE "cast_members" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"event_id" NUMERIC NOT NULL,
|
||||
"cast_name" TEXT,
|
||||
"role" TEXT,
|
||||
"images" JSON,
|
||||
"status" TEXT,
|
||||
"validFrom" DATE,
|
||||
"validTill" DATE,
|
||||
"createdAt" DATE,
|
||||
"updatedAt" DATE,
|
||||
"createdBy" TEXT,
|
||||
"modifiedBy" TEXT,
|
||||
"deletedAt" DATE,
|
||||
"version" NUMERIC
|
||||
);
|
||||
|
||||
CREATE TABLE "user_watchlist" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"user_id" NUMERIC NOT NULL,
|
||||
"event_id" NUMERIC NOT NULL,
|
||||
"status" TEXT,
|
||||
"validFrom" DATE,
|
||||
"validTill" DATE,
|
||||
"createdAt" DATE,
|
||||
"updatedAt" DATE,
|
||||
"createdBy" TEXT,
|
||||
"modifiedBy" TEXT,
|
||||
"deletedAt" DATE,
|
||||
"version" NUMERIC
|
||||
);
|
||||
|
||||
CREATE TABLE "event_analytics" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"event_id" NUMERIC NOT NULL,
|
||||
"views" NUMERIC,
|
||||
"ticket_sales" NUMERIC,
|
||||
"engagement_rate" NUMERIC,
|
||||
"promotion_views" NUMERIC,
|
||||
"promotion_sales" NUMERIC,
|
||||
"status" TEXT,
|
||||
"validFrom" DATE,
|
||||
"validTill" DATE,
|
||||
"createdAt" DATE,
|
||||
"updatedAt" DATE,
|
||||
"createdBy" TEXT,
|
||||
"modifiedBy" TEXT,
|
||||
"deletedAt" DATE,
|
||||
"version" NUMERIC
|
||||
);
|
||||
|
||||
CREATE TABLE "locations" (
|
||||
"id" BIGSERIAL PRIMARY KEY NOT NULL,
|
||||
"name" TEXT,
|
||||
"code" TEXT,
|
||||
"images" TEXT[],
|
||||
"status" TEXT,
|
||||
"validFrom" DATE,
|
||||
"validTill" DATE,
|
||||
"createdAt" DATE,
|
||||
"updatedAt" DATE,
|
||||
"createdBy" TEXT,
|
||||
"modifiedBy" TEXT,
|
||||
"deletedAt" DATE,
|
||||
"version" NUMERIC
|
||||
);
|
||||
|
||||
|
||||
|
||||
830
package-lock.json
generated
830
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@ -24,25 +24,35 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/axios": "^4.0.0",
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/common": "^10.4.15",
|
||||
"@nestjs/config": "^3.3.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@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",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"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",
|
||||
"passport-google-oauth20": "^2.0.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"pg": "^8.14.1",
|
||||
"reflect-metadata": "^0.1.14",
|
||||
"rxjs": "^7.8.1",
|
||||
"sequelize": "^6.35.2",
|
||||
"sequelize-typescript": "^2.1.6",
|
||||
"socket.io": "^4.8.1",
|
||||
"typeorm": "^0.3.17",
|
||||
"web-push": "^3.6.7"
|
||||
},
|
||||
@ -56,6 +66,7 @@
|
||||
"@types/node": "^20.10.6",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/passport": "^1.0.17",
|
||||
"@types/passport-google-oauth20": "^2.0.16",
|
||||
"@types/passport-jwt": "^4.0.1",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@types/validator": "^13.11.7",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { ActionsService } from './actions.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
@ -50,6 +50,7 @@ export class ActionsController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() actions: Actions, @Res() res: Response) {
|
||||
if(!actions) {
|
||||
const response = new GenericResponse({
|
||||
|
||||
@ -25,7 +25,7 @@ export class ActionsService {
|
||||
return Actions.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(actions: Actions, insertIfNotFound: boolean): Promise<Actions | [affectedCount: number]> {
|
||||
async upsert(actions: any, insertIfNotFound: boolean): Promise<Actions | [affectedCount: number]> {
|
||||
if (actions.id) {
|
||||
const existingActions = await this.findByPk(actions.id);
|
||||
if (existingActions) {
|
||||
|
||||
@ -49,4 +49,16 @@ export class AppConfigService {
|
||||
getVapidConfig(){
|
||||
return configMaster[this.defaultEnv].vapidConfig;
|
||||
}
|
||||
|
||||
getRedisConfig(){
|
||||
return configMaster[this.defaultEnv].redisConfig;
|
||||
}
|
||||
|
||||
getSwaggerConfig(){
|
||||
return configMaster[this.defaultEnv].swaggerConfig;
|
||||
}
|
||||
|
||||
getGoogleOauthConfig(){
|
||||
return configMaster[this.defaultEnv].googleOauthConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
"port": 3003
|
||||
},
|
||||
"dbConfig": {
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"host": "192.168.0.113",
|
||||
"port": 5431,
|
||||
"user": "postgres",
|
||||
"password": "postgres",
|
||||
"password": "FAdDoCwhmi3BvkK4pgEGDc7EspmDtHYV4y93748Xz6VysJKPdlsaU3L9N9k7OD9t",
|
||||
"database": "epr",
|
||||
"MODE": "DEV",
|
||||
"loggerEnabled": true
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
"port": 3000
|
||||
},
|
||||
"dbConfig": {
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"host": "192.168.0.113",
|
||||
"port": 5431,
|
||||
"user": "postgres",
|
||||
"password": "postgres",
|
||||
"password": "FAdDoCwhmi3BvkK4pgEGDc7EspmDtHYV4y93748Xz6VysJKPdlsaU3L9N9k7OD9t",
|
||||
"database": "ticket_booking_db",
|
||||
"MODE": "DEV",
|
||||
"loggerEnabled": true
|
||||
@ -53,8 +53,24 @@
|
||||
},
|
||||
"vapidConfig": {
|
||||
"email": "mailto:example@domain.com",
|
||||
"publicKey": "BPcIQx6jQlD0m2WA5qzXnHtKtsBhvIf_aRf6foXx3ESiw2Tks6b8tVzzX3hHwerGtWy4togFEiJtk5X-Sq36uVQ",
|
||||
"privateKey": "v-pRrypniFnPn6UOyDNIKatxoHCI6aqsXCM86L7aTfY"
|
||||
"publicKey": "BJnRhhooOB7unX8yfpHXgbUVqR03A7zsAppguA7JfHMNmhgZ1-RqbA-y70neaPrtbfO8Q1GsipYIM05_SpLDUP0",
|
||||
"privateKey": "7OAq3PXC3VCNPus6Mua9rxSO66Vd0j5J5Mv8g7hMbYc"
|
||||
},
|
||||
"redisConfig": {
|
||||
"host": "192.168.0.113",
|
||||
"port": 6379,
|
||||
"db": 0,
|
||||
"username": "default",
|
||||
"password":"oRYKRJKppvVqmSvTCiGeqVF4DDiFc22g6zodJQwbZCxNvKI34UYoQ8bMqdfDtmqd"
|
||||
},
|
||||
"googleOauthConfig": {
|
||||
"clientId": "361418022886-q8inm4gh7aqhopitpsl87m0vcgces320.apps.googleusercontent.com",
|
||||
"clientSecret": "GOCSPX-TwyERXKjx-8_U1X68ayJpCssfY",
|
||||
"callbackURL": "http://localhost:3000/auth/google-redirect",
|
||||
"scope": [
|
||||
"email",
|
||||
"profile"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,10 +4,10 @@
|
||||
"port": 3000
|
||||
},
|
||||
"dbConfig": {
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"host": "192.168.0.113",
|
||||
"port": 5431,
|
||||
"user": "postgres",
|
||||
"password": "postgres",
|
||||
"password": "FAdDoCwhmi3BvkK4pgEGDc7EspmDtHYV4y93748Xz6VysJKPdlsaU3L9N9k7OD9t",
|
||||
"database": "ticket_booking_db",
|
||||
"MODE": "DEV",
|
||||
"loggerEnabled": true
|
||||
@ -53,8 +53,24 @@
|
||||
},
|
||||
"vapidConfig": {
|
||||
"email": "mailto:example@domain.com",
|
||||
"publicKey": "BPcIQx6jQlD0m2WA5qzXnHtKtsBhvIf_aRf6foXx3ESiw2Tks6b8tVzzX3hHwerGtWy4togFEiJtk5X-Sq36uVQ",
|
||||
"privateKey": "v-pRrypniFnPn6UOyDNIKatxoHCI6aqsXCM86L7aTfY"
|
||||
"publicKey": "BJnRhhooOB7unX8yfpHXgbUVqR03A7zsAppguA7JfHMNmhgZ1-RqbA-y70neaPrtbfO8Q1GsipYIM05_SpLDUP0",
|
||||
"privateKey": "7OAq3PXC3VCNPus6Mua9rxSO66Vd0j5J5Mv8g7hMbYc"
|
||||
},
|
||||
"redisConfig": {
|
||||
"host": "192.168.0.113",
|
||||
"port": 6379,
|
||||
"db": 0,
|
||||
"username": "default",
|
||||
"password":"oRYKRJKppvVqmSvTCiGeqVF4DDiFc22g6zodJQwbZCxNvKI34UYoQ8bMqdfDtmqd"
|
||||
},
|
||||
"googleOauthConfig": {
|
||||
"clientId": "361418022886-q8inm4gh7aqhopitpsl87m0vcgces320.apps.googleusercontent.com",
|
||||
"clientSecret": "GOCSPX-TwyERXKjx-8_U1X68ayJpCssfY",
|
||||
"callbackURL": "http://localhost:3000/auth/google-redirect",
|
||||
"scope": [
|
||||
"email",
|
||||
"profile"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,10 +4,10 @@
|
||||
"port": 3003
|
||||
},
|
||||
"dbConfig": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 5432,
|
||||
"host": "192.168.0.113",
|
||||
"port": 5431,
|
||||
"user": "postgres",
|
||||
"password": "postgres",
|
||||
"password": "FAdDoCwhmi3BvkK4pgEGDc7EspmDtHYV4y93748Xz6VysJKPdlsaU3L9N9k7OD9t",
|
||||
"database": "epr",
|
||||
"MODE": "PROD",
|
||||
"loggerEnabled": true
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
"port": 3003
|
||||
},
|
||||
"dbConfig": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 5432,
|
||||
"host": "192.168.0.113",
|
||||
"port": 5431,
|
||||
"user": "postgres",
|
||||
"password": "postgres",
|
||||
"password": "FAdDoCwhmi3BvkK4pgEGDc7EspmDtHYV4y93748Xz6VysJKPdlsaU3L9N9k7OD9t",
|
||||
"database": "epr",
|
||||
"MODE": "TEST",
|
||||
"loggerEnabled": true
|
||||
|
||||
@ -21,6 +21,9 @@ import { TicketModule } from './ticket/ticket.module';
|
||||
import { TicketPricingModule } from './ticketPricing/ticketPricing.module';
|
||||
import { TimeSlotModule } from './timeSlot/timeSlot.module';
|
||||
import { PushSubscriptionModule } from './push-subscription/push-subscription.module';
|
||||
import { RedisModule } from './redis/redis.module';
|
||||
import { BookingGatewayModule } from './booking-gateway/booking-gateway.module';
|
||||
import { LocationsModule } from './locations/locations.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -40,7 +43,10 @@ import { PushSubscriptionModule } from './push-subscription/push-subscription.mo
|
||||
TicketPricingModule,
|
||||
TimeSlotModule,
|
||||
UserModule,
|
||||
PushSubscriptionModule
|
||||
PushSubscriptionModule,
|
||||
RedisModule,
|
||||
BookingGatewayModule,
|
||||
LocationsModule
|
||||
|
||||
],
|
||||
controllers: [AppController, AppConfigController],
|
||||
|
||||
@ -18,20 +18,24 @@ export class AppService {
|
||||
return 'Hello World!';
|
||||
}
|
||||
|
||||
initializeSequelize() {
|
||||
async initializeSequelize() {
|
||||
this.getModels();
|
||||
const dbConfig = this.configService.getDbConfig();
|
||||
if (this.modelFilePaths.length > 0) {
|
||||
this.commonService.sequelize = new Sequelize({
|
||||
database: dbConfig.database,
|
||||
database: "ticket_booking_db",
|
||||
host: "192.168.0.113", // <-- IP or hostname of your DB
|
||||
port: 5431,
|
||||
dialect: 'postgres',
|
||||
username: dbConfig.user,
|
||||
password: dbConfig.password,
|
||||
username: "postgres",
|
||||
password: "FAdDoCwhmi3BvkK4pgEGDc7EspmDtHYV4y93748Xz6VysJKPdlsaU3L9N9k7OD9t",
|
||||
|
||||
models: this.modelFilePaths,
|
||||
modelMatch: (filename, member) => {
|
||||
return filename.substring(0, filename.indexOf('.entity')) === member.toLowerCase();
|
||||
},
|
||||
});
|
||||
await this.commonService.sequelize.sync({ alter: true });
|
||||
Utility.sequelize = this.commonService.sequelize;
|
||||
}
|
||||
const fileConfig = this.configService.initializeFileSystem();
|
||||
@ -45,9 +49,22 @@ export class AppService {
|
||||
const jwtConfig = this.configService.getJwtConfig();
|
||||
this.commonService.jwtConfig = jwtConfig;
|
||||
Utility.jwtConfig = jwtConfig;
|
||||
// const urlConfig = this.configService.getUrlConfig();
|
||||
// this.commonService.urlConfig = urlConfig;
|
||||
// Utility.urlConfig = urlConfig;
|
||||
|
||||
const vapidConfig = this.configService.getVapidConfig();
|
||||
this.commonService.vapidConfig = vapidConfig;
|
||||
Utility.vapidConfig = vapidConfig;
|
||||
|
||||
const swaggerConfig = this.configService.getSwaggerConfig();
|
||||
this.commonService.swaggerConfig = swaggerConfig;
|
||||
Utility.swaggerConfig = swaggerConfig;
|
||||
|
||||
const redisConfig = this.configService.getRedisConfig();
|
||||
this.commonService.redisConfig = redisConfig;
|
||||
Utility.redisConfig = redisConfig;
|
||||
|
||||
const googleOauthConfig = this.configService.getGoogleOauthConfig();
|
||||
this.commonService.googleOauthConfig = googleOauthConfig;
|
||||
Utility.googleOauthConfig = googleOauthConfig;
|
||||
}
|
||||
|
||||
getModels() {
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
import { Body, Controller, Delete, Post, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Post, Req, Res, UseGuards } from '@nestjs/common';
|
||||
import { GenericResponse } from 'src/common/GenericResponse.model';
|
||||
import { AuthService } from './auth.service';
|
||||
import { Response } from 'express';
|
||||
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';
|
||||
import { ForgotPasswordDto, LoginDto, ResetPasswordDto, SignupDto, VerifyCodeDto } from './auth.dto';
|
||||
import { MailService } from 'src/mail/mail.service';
|
||||
|
||||
@ApiTags('Auth')
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private authService: AuthService) { }
|
||||
constructor(private authService: AuthService, private userService: UserService, private mailService: MailService) { }
|
||||
|
||||
@Post('login')
|
||||
@ApiOperation({ summary: 'Login' })
|
||||
@ -27,7 +33,7 @@ export class AuthController {
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
async login(@Body() userDto: { email: string; password: string }, @Res() res: Response) {
|
||||
async login(@Body() userDto: LoginDto, @Res() res: Response) {
|
||||
const user = await this.authService.validateUser(userDto);
|
||||
if (!user) {
|
||||
const errorResponse = new GenericResponse({
|
||||
@ -39,34 +45,140 @@ export class AuthController {
|
||||
res.status(404).send(errorResponse);
|
||||
}
|
||||
const tokens = await this.authService.login(user);
|
||||
const httpResponse = new GenericResponse(null, tokens);
|
||||
|
||||
res.header('Authorization', 'Bearer ' + tokens.access_token);
|
||||
|
||||
res.cookie('refresh_token', tokens.refresh_token, {
|
||||
httpOnly: true,
|
||||
secure: false,
|
||||
sameSite: 'lax',
|
||||
path: '/'
|
||||
});
|
||||
const httpResponse = new GenericResponse(null, {
|
||||
// id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
userTypeCode: user.userTypeCode,
|
||||
});
|
||||
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);
|
||||
// console.log("new token is",newToken);
|
||||
if (!newToken) {
|
||||
@Post('signup')
|
||||
async signup(@Body() userDto: SignupDto, @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: 'Token not found'
|
||||
}, null)
|
||||
res.status(404).send(errorResponse);
|
||||
stackTrace: 'User already exists'
|
||||
}, null);
|
||||
res.status(401).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, newToken);
|
||||
res.status(201).send(httpResponse);
|
||||
const userCreated = await this.userService.upsert(userDto, true);
|
||||
const tokens = await this.authService.login(userCreated);
|
||||
res.header('Authorization', 'Bearer ' + tokens.access_token);
|
||||
res.cookie('refresh_token', tokens.refresh_token, {
|
||||
httpOnly: true,
|
||||
secure: false,
|
||||
sameSite: 'lax',
|
||||
path: '/'
|
||||
})
|
||||
const httpResponse = new GenericResponse(null,
|
||||
{
|
||||
email: tokens.email,
|
||||
name: tokens.name,
|
||||
userTypeCode: tokens.userTypeCode,
|
||||
}
|
||||
);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
|
||||
@Post('refresh')
|
||||
async refresh(@Req() req: Request, @Res() res: Response) {
|
||||
console.log("req.cookies");
|
||||
console.log(req.cookies);
|
||||
console.log('headers:', req.headers.cookie);
|
||||
|
||||
const refreshToken = req.cookies['refresh_token'];
|
||||
if (!refreshToken) {
|
||||
return res.status(401).json({ message: 'Refresh token missing' });
|
||||
}
|
||||
try {
|
||||
const newToken = await this.authService.refreshAccessToken(refreshToken);
|
||||
|
||||
res.header('Authorization', 'Bearer ' + newToken.access_token);
|
||||
return res.status(200).json(new GenericResponse(null, {
|
||||
email: newToken.email,
|
||||
name: newToken.name,
|
||||
userTypeCode: newToken.userTypeCode
|
||||
}));
|
||||
} catch (err) {
|
||||
return res.status(403).json({
|
||||
message: 'Invalid or expired refresh token',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Post('forgot-password')
|
||||
@ApiOperation({ summary: 'Send reset code to email' })
|
||||
async forgotPassword(@Body() dto: ForgotPasswordDto, @Res() res: Response) {
|
||||
await this.authService.sendResetCode(dto.email);
|
||||
return res.status(200).send(new GenericResponse(null, {
|
||||
message: 'If your email is registered, a code has been sent.',
|
||||
}));
|
||||
}
|
||||
|
||||
@Post('verify-reset-code')
|
||||
@ApiOperation({ summary: 'Verify 4-digit reset code' })
|
||||
async verifyCode(@Body() dto: VerifyCodeDto, @Res() res: Response) {
|
||||
const isValid = await this.authService.verifyResetCode(dto.email, dto.code);
|
||||
if (!isValid) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_OR_EXPIRED_CODE',
|
||||
stackTrace: 'Code is invalid or expired',
|
||||
}, null));
|
||||
}
|
||||
|
||||
return res.status(200).send(new GenericResponse(null, {
|
||||
message: 'Code verified successfully.',
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@Post('reset-password')
|
||||
@ApiOperation({ summary: 'Reset password using code' })
|
||||
async resetPassword(@Body() dto: ResetPasswordDto, @Res() res: Response) {
|
||||
const success = await this.authService.resetPasswordWithCode(dto.email, dto.code, dto.password);
|
||||
|
||||
if (!success) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_OR_EXPIRED_CODE',
|
||||
stackTrace: 'Code is invalid or expired',
|
||||
}, null));
|
||||
}
|
||||
|
||||
return res.status(200).send(new GenericResponse(null, {
|
||||
message: 'Password has been reset successfully.',
|
||||
}));
|
||||
}
|
||||
|
||||
@Delete('logout')
|
||||
delete(@Body() body: { refresh_token: string }, @Res() res: Response) {
|
||||
const deleteToken = this.authService.logout(body.refresh_token);
|
||||
delete(@Res() res: Response, @Req() req: Request) {
|
||||
const refreshToken = req.cookies['refresh_token'];
|
||||
const deleteToken = this.authService.logout(refreshToken);
|
||||
res.status(200).send(deleteToken);
|
||||
}
|
||||
|
||||
@Post('verifyAccess')
|
||||
// @Post('verifyAccess')
|
||||
async verifyAccessToken(@Body() body: { access_token: string }, @Res() res: Response) {
|
||||
const token = await this.authService.verifyAccessToken(body.access_token);
|
||||
if (token) {
|
||||
@ -83,7 +195,7 @@ export class AuthController {
|
||||
}
|
||||
}
|
||||
|
||||
@Post('verifyRefresh')
|
||||
// @Post('verifyRefresh')
|
||||
async verifyRefreshToken(@Body() body: { refresh_token: string }, @Res() res: Response) {
|
||||
const token = await this.authService.verifyRefreshToken(body.refresh_token);
|
||||
if (token) {
|
||||
@ -100,4 +212,26 @@ export class AuthController {
|
||||
}
|
||||
}
|
||||
|
||||
//google oauth implementation
|
||||
|
||||
@Get()
|
||||
@UseGuards(GoogleOauthGuard)
|
||||
async googleLogin(@Res() res: Response) {
|
||||
console.log("inside google login");
|
||||
} //basically this is used to call googleLogin for login credentials
|
||||
|
||||
@Get('google-redirect')
|
||||
@UseGuards(GoogleOauthGuard)
|
||||
async googleOauthRedirect(@Req() req: Request, @Res() res: Response) {
|
||||
console.log("inside google redirect");
|
||||
const httpResponse = await this.authService.googleOauthRedirect(req.user);
|
||||
res.header('Authorization', 'Bearer ' + httpResponse.access_token);
|
||||
res.cookie('refresh_token', httpResponse.refresh_token, {
|
||||
httpOnly: true,
|
||||
secure: false,
|
||||
sameSite: 'lax',
|
||||
path: '/'
|
||||
})
|
||||
return res.status(httpResponse.statusCode).send();
|
||||
}
|
||||
}
|
||||
|
||||
101
src/auth/auth.dto.ts
Normal file
101
src/auth/auth.dto.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsEmail, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, MinLength } from 'class-validator';
|
||||
|
||||
export class SignupDto {
|
||||
@ApiProperty({
|
||||
description: 'User email address',
|
||||
example: 'user@example.com',
|
||||
})
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'User phone number in international format',
|
||||
example: '+1234567890',
|
||||
})
|
||||
@IsPhoneNumber(null)
|
||||
@IsOptional()
|
||||
@IsNotEmpty()
|
||||
phoneNumber?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'User full name (optional)',
|
||||
example: 'John Doe',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
name?: string;
|
||||
|
||||
@ApiProperty({
|
||||
// description: 'Password with a minimum of 6 characters',
|
||||
example: 'securePassword123',
|
||||
})
|
||||
@IsString()
|
||||
// @MinLength(6)
|
||||
@IsNotEmpty()
|
||||
password: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'User type code',
|
||||
example: 'ADMIN',
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
userTypeCode: string
|
||||
}
|
||||
|
||||
|
||||
export class LoginDto {
|
||||
@ApiProperty({
|
||||
description: 'User email address',
|
||||
example: 'user@example.com',
|
||||
})
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
|
||||
@ApiProperty({
|
||||
// description: 'Password with a minimum of 6 characters',
|
||||
example: 'securePassword123',
|
||||
})
|
||||
@IsString()
|
||||
// @MinLength(6)
|
||||
@IsNotEmpty()
|
||||
password: string;
|
||||
}
|
||||
|
||||
export class ForgotPasswordDto {
|
||||
@ApiProperty({ example: 'user@example.com' })
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
}
|
||||
|
||||
export class VerifyCodeDto {
|
||||
@ApiProperty({ example: 'user@example.com' })
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
|
||||
@ApiProperty({ example: '1234' })
|
||||
@IsString()
|
||||
code: string;
|
||||
}
|
||||
|
||||
|
||||
export class ResetPasswordDto {
|
||||
@ApiProperty({ example: 'user@example.com' })
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
|
||||
@ApiProperty({ example: '1234' })
|
||||
@IsString()
|
||||
code: string;
|
||||
|
||||
@ApiProperty({ example: 'newStrongPassword123' })
|
||||
@IsString()
|
||||
@MinLength(6)
|
||||
password: string;
|
||||
}
|
||||
@ -7,6 +7,8 @@ import { UserModule } from 'src/user/user.module';
|
||||
import { JwtStrategy } from 'src/jwt/jwt.strategy';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { GoogleStrategy } from 'src/google-oauth/google.strategy';
|
||||
import { MailModule } from 'src/mail/mail.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -24,9 +26,10 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
inject: [ConfigService],
|
||||
}),
|
||||
UserModule,
|
||||
MailModule
|
||||
],
|
||||
controllers: [AuthController],
|
||||
providers: [AuthService, JwtStrategy],
|
||||
providers: [AuthService, JwtStrategy,GoogleStrategy],
|
||||
exports: [AuthService],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { Response } from 'express';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
import JwtPayload from 'src/jwt/jwt-payload.dto';
|
||||
import RefreshToken from 'src/jwt/refresh-token.entity';
|
||||
import { User } from 'src/user/user.entity';
|
||||
import { UserService } from 'src/user/user.service';
|
||||
import { Request } from 'express';
|
||||
import * as crypto from 'crypto';
|
||||
import { MailService } from 'src/mail/mail.service';
|
||||
import { instanceToPlain } from 'class-transformer';
|
||||
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(private userService: UserService, private jwtService: JwtService) { }
|
||||
|
||||
private signToken(payload: any, type: 'accessToken' | 'refreshToken'): string {
|
||||
console.log("yav type andre", type)
|
||||
constructor(private userService: UserService, private jwtService: JwtService, private mailService: MailService) { }
|
||||
|
||||
private signToken(payload: any, type: 'accessToken' | 'refreshToken') {
|
||||
const config = Utility.jwtConfig[type];
|
||||
console.log("yav expiry andre", config.expiresIn)
|
||||
return this.jwtService.sign(payload, {
|
||||
secret: config.secretOrKey,
|
||||
expiresIn: config.expiresIn,
|
||||
@ -26,25 +33,39 @@ export class AuthService {
|
||||
secret: config.secretOrKey,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(`${type} token is invalid`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async validateUser(payload: JwtPayload) {
|
||||
return this.userService.findByEmail(payload.email);
|
||||
async validateUser(payload: any) {
|
||||
return this.userService.findByEmailWithPassword(payload.email, payload.password);
|
||||
}
|
||||
|
||||
async login(user: any) {
|
||||
const payload: JwtPayload = { email: user.email, password: user.password };
|
||||
console.log("illig bandu nilthu", payload)
|
||||
// const plainUser = instanceToPlain(user);
|
||||
const payload = {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
userTypeCode: user.userTypeCode,
|
||||
};
|
||||
const accessToken = this.signToken(payload, 'accessToken');
|
||||
console.log("illig bandu nilthu", accessToken)
|
||||
|
||||
const refreshToken = this.signToken(payload, 'refreshToken');
|
||||
await RefreshToken.create({ email: user.email, token: refreshToken, type: 'jwt' });
|
||||
return {
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
userTypeCode: user.userTypeCode,
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken,
|
||||
};
|
||||
}
|
||||
|
||||
await RefreshToken.create({ email: user.email, token: refreshToken });
|
||||
|
||||
async signup(user: any) {
|
||||
const { password, ...rest } = user;
|
||||
const payload = { rest };
|
||||
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,
|
||||
@ -56,38 +77,117 @@ export class AuthService {
|
||||
if (!payload) {
|
||||
throw new Error('Invalid refresh token');
|
||||
}
|
||||
|
||||
console.log(refreshToken);
|
||||
console.log(payload);
|
||||
const user = await this.userService.findByEmail(payload.email);
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
console.log(user)
|
||||
const accessToken = this.signToken({
|
||||
email: payload.email
|
||||
}, 'accessToken');
|
||||
console.log(accessToken)
|
||||
return { access_token: accessToken };
|
||||
const newPayload = {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
userTypeCode: user.userTypeCode,
|
||||
};
|
||||
const accessToken = this.signToken(newPayload, 'accessToken');
|
||||
return {
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
userTypeCode: user.userTypeCode,
|
||||
access_token: accessToken
|
||||
};
|
||||
}
|
||||
|
||||
async verifyRefreshToken(refreshToken: string) {
|
||||
const payload = this.verifyToken(refreshToken, 'refreshToken');
|
||||
if (payload) {
|
||||
console.log("Refresh token is valid", payload);
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async verifyAccessToken(accessToken: string) {
|
||||
const payload = this.verifyToken(accessToken, 'accessToken');
|
||||
if (payload) {
|
||||
console.log("Access token is valid", payload);
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async logout(refreshToken: string) {
|
||||
return RefreshToken.destroy({ where: { token: refreshToken } });
|
||||
}
|
||||
|
||||
|
||||
async sendResetCode(email: string): Promise<void> {
|
||||
const user = await this.userService.findByEmail(email);
|
||||
if (!user) return;
|
||||
const plainUser = user.get({ plain: true });
|
||||
console.log("user", plainUser);
|
||||
const code = Math.floor(1000 + Math.random() * 9000).toString();
|
||||
const expires = new Date(Date.now() + 10 * 60 * 1000);
|
||||
// console.log("code", code);
|
||||
// console.log("expires", expires);
|
||||
user.resetCode = code;
|
||||
user.resetCodeExpires = expires;
|
||||
const updatedUser = await this.userService.update(plainUser);
|
||||
console.log("updatedUser", updatedUser);
|
||||
const subject = 'Your Password Reset Code';
|
||||
const html = `<p>Your reset code is <strong>${code}</strong>. It will expire in 10 minutes.</p>`;
|
||||
await this.mailService.sendMail(email, subject, `Code: ${code}`, html);
|
||||
}
|
||||
|
||||
async resetPasswordWithCode(email: string, code: string, password: string): Promise<boolean> {
|
||||
const userObj = await this.userService.findByEmail(email);
|
||||
const user = userObj.get({ plain: true });
|
||||
if (!user || user.resetCode != code) return false;
|
||||
|
||||
user.password = this.encryptPassword(password);
|
||||
user.resetCode = null;
|
||||
user.resetCodeExpires = null;
|
||||
await this.userService.update(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
async verifyResetCode(email: string, code: string): Promise<boolean> {
|
||||
const user = await this.userService.findByEmail(email);
|
||||
let plainUser = user.get({ plain: true });
|
||||
console.log("plainUser", plainUser);
|
||||
if (!plainUser || !plainUser.resetCode || !plainUser.resetCodeExpires) return false;
|
||||
return plainUser.resetCode == code.toString();
|
||||
}
|
||||
|
||||
//google services
|
||||
|
||||
async googleOauthRedirect(user) {
|
||||
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);
|
||||
// let existingUser = await User.findOne({ where: { email: user.email } });
|
||||
let existingUser = await this.userService.findByEmail(user.email);
|
||||
if (!existingUser) {
|
||||
existingUser = await User.create({
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
userTypeCode: 'user'
|
||||
});
|
||||
}
|
||||
|
||||
const newuser = await this.userService.findByEmail(user.email);
|
||||
const rest = {
|
||||
email: newuser.email,
|
||||
name: newuser.name,
|
||||
userTypeCode: newuser.userTypeCode,
|
||||
};
|
||||
|
||||
const payload = existingUser.get({ plain: true });
|
||||
// const { } = payload
|
||||
const accessToken = this.signToken(rest, 'accessToken');
|
||||
const refreshToken = this.signToken(rest, 'refreshToken');
|
||||
await RefreshToken.create({ email: payload.email, token: refreshToken, type: 'jwt' });
|
||||
return {
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken
|
||||
}
|
||||
}
|
||||
|
||||
encryptPassword(password: string) {
|
||||
return Buffer.from(password).toString('base64');
|
||||
}
|
||||
}
|
||||
|
||||
13
src/booking-gateway/booking-gateway.module.ts
Normal file
13
src/booking-gateway/booking-gateway.module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BookingGateway } from './booking.gateway';
|
||||
import { BookingService } from './booking.service';
|
||||
import { SeatService } from 'src/seat/seat.service';
|
||||
import { TicketService } from 'src/ticket/ticket.service';
|
||||
import { HttpModule, HttpService } from '@nestjs/axios';
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule],
|
||||
providers: [BookingService, BookingGateway, SeatService, TicketService],
|
||||
exports: [BookingService, BookingGateway],
|
||||
})
|
||||
export class BookingGatewayModule { }
|
||||
53
src/booking-gateway/booking.gateway.ts
Normal file
53
src/booking-gateway/booking.gateway.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { WebSocketServer, OnGatewayConnection, OnGatewayDisconnect, SubscribeMessage, MessageBody, WebSocketGateway } from '@nestjs/websockets';
|
||||
import { Server, Socket } from 'socket.io';
|
||||
import { BookingService } from './booking.service';
|
||||
import Ticket from 'src/ticket/ticket.entity';
|
||||
|
||||
@WebSocketGateway()
|
||||
export class BookingGateway implements OnGatewayConnection, OnGatewayDisconnect {
|
||||
|
||||
constructor(private readonly bookingService: BookingService) { }
|
||||
|
||||
@WebSocketServer()
|
||||
server: Server;
|
||||
|
||||
private connectedClients = 0;
|
||||
|
||||
handleConnection(client: Socket) {
|
||||
this.connectedClients++;
|
||||
console.log(`Client connected: ${client.id}`);
|
||||
this.server.emit('clientsUpdated', this.connectedClients);
|
||||
}
|
||||
|
||||
handleDisconnect(client: Socket) {
|
||||
this.connectedClients--;
|
||||
console.log(`Client disconnected: ${client.id}`);
|
||||
this.server.emit('clientsUpdated', this.connectedClients);
|
||||
}
|
||||
|
||||
@SubscribeMessage('bookTicket')
|
||||
async handleBookTicket(@MessageBody() ticket: Ticket) {
|
||||
const response = await this.bookingService.bookTicket(ticket);
|
||||
this.server.to(ticket.eventId.toString() ).emit('ticketBooked', response);
|
||||
this.server.emit('ticketBooked', response);
|
||||
}
|
||||
@SubscribeMessage('checkSeatAvailability')
|
||||
async handleCheckSeatAvailability(@MessageBody() data: { event_id: number, seatNumber: string }) {
|
||||
const { event_id: eventId, seatNumber } = data;
|
||||
const isAvailable = await this.bookingService.isSeatAvailable(eventId, seatNumber);
|
||||
this.server.emit('seatAvailability', { isAvailable });
|
||||
}
|
||||
|
||||
@SubscribeMessage('joinRoom')
|
||||
async handleJoinEvent(client: Socket,@MessageBody() data: { roomId: string }) {
|
||||
client.join(data.roomId);
|
||||
console.log(`Client joined room: ${data.roomId}`);
|
||||
this.server.to(data.roomId).emit('clientJoinedRoom');
|
||||
}
|
||||
|
||||
@SubscribeMessage('getBookedSeats')
|
||||
async handleGetBookedSeats(@MessageBody() movieId: string) {
|
||||
const bookedSeats = await this.bookingService.getBookedSeats(movieId);
|
||||
this.server.emit('bookedSeatsList', bookedSeats);
|
||||
}
|
||||
}
|
||||
31
src/booking-gateway/booking.service.ts
Normal file
31
src/booking-gateway/booking.service.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { BookingGateway } from './booking.gateway';
|
||||
import { SeatService } from 'src/seat/seat.service';
|
||||
import { TicketService } from 'src/ticket/ticket.service';
|
||||
import Ticket from 'src/ticket/ticket.entity';
|
||||
import Seat from 'src/seat/seat.entity';
|
||||
|
||||
@Injectable()
|
||||
export class BookingService {
|
||||
constructor(
|
||||
// @Inject('BookingGateway') private readonly bookingGateway: BookingGateway,
|
||||
private readonly seatService: SeatService,
|
||||
private readonly ticketService: TicketService
|
||||
) { }
|
||||
|
||||
async bookTicket(ticket: Ticket) {
|
||||
this.ticketService.upsert(ticket, true);
|
||||
this.seatService.bookSeat(ticket.eventId, ticket.seatNumber);
|
||||
}
|
||||
async getBookedSeats(event_id) {
|
||||
const bookedSeats = await this.seatService.filter(new Seat({ eventId: event_id, available: 'booked' }));
|
||||
return bookedSeats;
|
||||
}
|
||||
async isSeatAvailable(event_id: number, seatNumber: string) {
|
||||
const seat = await this.seatService.findOne(new Seat({ eventId: event_id, seatNumber: seatNumber }));
|
||||
if (seat.available === 'booked') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
312
src/cast/cast.controller.ts
Normal file
312
src/cast/cast.controller.ts
Normal file
@ -0,0 +1,312 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { CastService } from './cast.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
import Cast from './cast.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { CastDTO, CastUpdateDTO } from './cast.dto';
|
||||
|
||||
@ApiTags('cast')
|
||||
@Controller('cast')
|
||||
export class CastController {
|
||||
constructor(private castService: CastService) { }
|
||||
|
||||
@Get("/all")
|
||||
@ApiOperation({ summary: 'Get all casts' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully retrieved all casts',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No casts found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "No casts found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
async getAllCasts(@Res() res: Response) {
|
||||
const response = await this.castService.findAll() || [];
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No casts found'
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.send(httpResponse);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get cast by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Cast ID' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID is required',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NO_ID_REQ",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Cast not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Cast not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully retrieved cast by ID',
|
||||
})
|
||||
async findById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.castService.findByPk(id) || {};
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Cast with ID ${id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Post('/filter')
|
||||
@ApiOperation({ summary: 'Filter casts based on criteria' })
|
||||
@ApiBody({ type: Cast, description: 'Filter criteria for casts' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid filter criteria',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_CRITERIA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No casts found based on filter criteria',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "No casts found based on the filter criteria"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully filtered casts',
|
||||
})
|
||||
async filter(@Body() cast: Cast, @Res() res: Response) {
|
||||
if (!cast) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_CRITERIA',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.castService.filter(cast) || [];
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No casts found based on the filter criteria'
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new cast' })
|
||||
@ApiBody({ type: CastDTO, description: 'Cast data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid cast data',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_DATA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 201,
|
||||
description: 'Successfully created a cast',
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() cast: CastDTO, @Res() res: Response) {
|
||||
if (!cast) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_DATA',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.castService.upsert(cast, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
}
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing cast' })
|
||||
@ApiBody({ type: CastUpdateDTO, description: 'Cast data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid cast data or ID missing',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_DATA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Cast not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Cast not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully updated cast',
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() cast: CastUpdateDTO, @Res() res: Response) {
|
||||
if (!cast || !cast.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.castService.upsert(cast, false);
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Cast with ID ${cast.id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete a cast by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Cast ID to delete' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID parameter is required',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NO_ID_REQ",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Cast not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Cast not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully deleted cast',
|
||||
})
|
||||
async deleteById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.castService.remove(id) || {};
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Cast with ID ${id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
}
|
||||
79
src/cast/cast.dto.ts
Normal file
79
src/cast/cast.dto.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
|
||||
export class CastDTO {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
castName: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
role: string;
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
@IsOptional()
|
||||
images: object;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
@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 CastUpdateDTO extends CastDTO {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
id: number;
|
||||
}
|
||||
58
src/cast/cast.entity.ts
Normal file
58
src/cast/cast.entity.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { Table, Column, Model, DataType } from 'sequelize-typescript';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
@Table({ tableName: 'cast_members', paranoid: true })
|
||||
export default class Cast extends Model {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, allowNull: false, field: 'event_id' })
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'cast_name' })
|
||||
castName: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'role' })
|
||||
role: string;
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
@Column({ type: DataType.JSON, field: 'images' })
|
||||
images: object;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'status' })
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validFrom' })
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validTill' })
|
||||
validTill: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'createdAt' })
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'updatedAt' })
|
||||
updatedAt: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'createdBy' })
|
||||
createdBy: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'modifiedBy' })
|
||||
modifiedBy: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'deletedAt' })
|
||||
deletedAt: Date;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'version' })
|
||||
version: number;
|
||||
}
|
||||
11
src/cast/cast.module.ts
Normal file
11
src/cast/cast.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CastController } from './cast.controller';
|
||||
import { CastService } from './cast.service';
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule],
|
||||
providers: [CastService],
|
||||
controllers: [CastController],
|
||||
})
|
||||
export class CastModule { }
|
||||
41
src/cast/cast.service.ts
Normal file
41
src/cast/cast.service.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import Cast from './cast.entity';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
|
||||
@Injectable()
|
||||
export class CastService {
|
||||
constructor(private readonly httpService: HttpService) { }
|
||||
|
||||
async findAll(): Promise<{ rows: Cast[], count: number }> {
|
||||
return Cast.findAndCountAll();
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<Cast> {
|
||||
return Cast.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(cast: Cast): Promise<Cast> {
|
||||
return Cast.findOne({ where: cast as any });
|
||||
}
|
||||
|
||||
filter(cast: Cast): Promise<Cast[]> {
|
||||
return Cast.findAll({ where: cast as any });
|
||||
}
|
||||
|
||||
async remove(id: number): Promise<number> {
|
||||
return Cast.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(cast: any, insertIfNotFound: boolean): Promise<Cast | [affectedCount: number]> {
|
||||
if (cast.id) {
|
||||
const existingCast = await this.findByPk(cast.id);
|
||||
if (existingCast) {
|
||||
return Cast.update(cast, { where: { id: cast.id } });
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
return Cast.create(cast as any);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,4 +23,6 @@ export class Utility {
|
||||
};
|
||||
static urlConfig:any;
|
||||
static vapidConfig: any;
|
||||
static redisConfig: any;
|
||||
static googleOauthConfig: any;
|
||||
}
|
||||
@ -10,6 +10,9 @@ export class CommonService {
|
||||
urlConfig:any;
|
||||
jwtConfig:any;
|
||||
vapidConfig:any;
|
||||
redisConfig:any;
|
||||
swaggerConfig:any;
|
||||
googleOauthConfig:any;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
63
src/common/files.service.ts
Normal file
63
src/common/files.service.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
287
src/event-analytics/event-analytics.controller.ts
Normal file
287
src/event-analytics/event-analytics.controller.ts
Normal file
@ -0,0 +1,287 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { EventAnalyticsService } from './event-analytics.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
import EventAnalytics from './event-analytics.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { EventAnalyticsDTO, EventAnalyticsUpdateDTO } from './event-analytics.dto';
|
||||
|
||||
@ApiTags('event-analytics')
|
||||
@Controller('event-analytics')
|
||||
export class EventAnalyticsController {
|
||||
constructor(private eventAnalyticsService: EventAnalyticsService) {}
|
||||
|
||||
@Get('/all')
|
||||
@ApiOperation({ summary: 'Get all event analytics' })
|
||||
@ApiResponse({ status: 200, description: 'Successfully retrieved all event analytics' })
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No event analytics found',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event analytics found'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
async getAll(@Res() res: Response) {
|
||||
const response = await this.eventAnalyticsService.findAll();
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event analytics found'
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
res.send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get event analytics by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Event analytics ID' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID is required',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event analytics not found',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'Event analytics not found'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({ status: 200, description: 'Successfully retrieved event analytics by ID' })
|
||||
async findById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
|
||||
const response = await this.eventAnalyticsService.findByPk(id);
|
||||
if (!response) {
|
||||
return res.status(404).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event analytics with ID ${id} not found`
|
||||
}, null));
|
||||
}
|
||||
|
||||
res.status(200).send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Post('/filter')
|
||||
@ApiOperation({ summary: 'Filter event analytics based on criteria' })
|
||||
@ApiBody({ type: EventAnalytics, description: 'Filter criteria for event analytics' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid filter criteria',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_CRITERIA',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No event analytics found based on filter criteria',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event analytics found based on the filter criteria'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({ status: 200, description: 'Successfully filtered event analytics' })
|
||||
async filter(@Body() analytics: EventAnalytics, @Res() res: Response) {
|
||||
if (!analytics) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_CRITERIA',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
|
||||
const response = await this.eventAnalyticsService.filter(analytics) || [];
|
||||
if (!response.length) {
|
||||
return res.status(404).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event analytics found based on the filter criteria'
|
||||
}, null));
|
||||
}
|
||||
|
||||
res.status(200).send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new event analytics record' })
|
||||
@ApiBody({ type: EventAnalyticsDTO, description: 'Event analytics data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid event analytics data',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_DATA',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({ status: 201, description: 'Successfully created event analytics record' })
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() analytics: EventAnalyticsDTO, @Res() res: Response) {
|
||||
if (!analytics) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_DATA',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
const response = await this.eventAnalyticsService.upsert(analytics, true);
|
||||
res.status(201).send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing event analytics record' })
|
||||
@ApiBody({ type: EventAnalyticsUpdateDTO, description: 'Event analytics data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid event analytics data or ID missing',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event analytics record not found',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'Event analytics not found'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({ status: 200, description: 'Successfully updated event analytics record' })
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() analytics: EventAnalyticsUpdateDTO, @Res() res: Response) {
|
||||
if (!analytics || !analytics.id) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
|
||||
const response = await this.eventAnalyticsService.upsert(analytics, false);
|
||||
if (!response) {
|
||||
return res.status(404).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event analytics with ID ${analytics.id} not found`
|
||||
}, null));
|
||||
}
|
||||
|
||||
res.status(200).send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete event analytics by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Event analytics ID to delete' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID parameter is required',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event analytics record not found',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'Event analytics not found'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({ status: 200, description: 'Successfully deleted event analytics record' })
|
||||
async deleteById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
|
||||
const response = await this.eventAnalyticsService.remove(id);
|
||||
if (!response) {
|
||||
return res.status(404).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event analytics with ID ${id} not found`
|
||||
}, null));
|
||||
}
|
||||
|
||||
res.status(200).send(new GenericResponse(null, response));
|
||||
}
|
||||
}
|
||||
92
src/event-analytics/event-analytics.dto.ts
Normal file
92
src/event-analytics/event-analytics.dto.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
|
||||
export class EventAnalyticsDTO {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
views: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
ticketSales: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
engagementRate: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
promotionViews: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
promotionSales: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
validTill: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
updatedAt: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
createdBy: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsOptional()
|
||||
@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 EventAnalyticsUpdateDTO extends EventAnalyticsDTO {
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
id: number;
|
||||
}
|
||||
66
src/event-analytics/event-analytics.entity.ts
Normal file
66
src/event-analytics/event-analytics.entity.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { Table, Column, Model, DataType } from 'sequelize-typescript';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
@Table({ tableName: 'event_analytics', paranoid: true })
|
||||
export default class EventAnalytics extends Model {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, allowNull: false, field: 'event_id' })
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'views' })
|
||||
views: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'ticket_sales' })
|
||||
ticketSales: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'engagement_rate' })
|
||||
engagementRate: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'promotion_views' })
|
||||
promotionViews: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'promotion_sales' })
|
||||
promotionSales: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'status' })
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validFrom' })
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validTill' })
|
||||
validTill: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'createdAt' })
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'updatedAt' })
|
||||
updatedAt: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'createdBy' })
|
||||
createdBy: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'modifiedBy' })
|
||||
modifiedBy: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'deletedAt' })
|
||||
deletedAt: Date;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'version' })
|
||||
version: number;
|
||||
}
|
||||
11
src/event-analytics/event-analytics.module.ts
Normal file
11
src/event-analytics/event-analytics.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { EventAnalyticsController } from './event-analytics.controller';
|
||||
import { EventAnalyticsService } from './event-analytics.service';
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule],
|
||||
providers: [EventAnalyticsService],
|
||||
controllers: [EventAnalyticsController],
|
||||
})
|
||||
export class EventAnalyticsModule { }
|
||||
41
src/event-analytics/event-analytics.service.ts
Normal file
41
src/event-analytics/event-analytics.service.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import EventAnalytics from './event-analytics.entity';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
|
||||
@Injectable()
|
||||
export class EventAnalyticsService {
|
||||
constructor(private readonly httpService: HttpService) {}
|
||||
|
||||
async findAll(): Promise<{ rows: EventAnalytics[], count: number }> {
|
||||
return EventAnalytics.findAndCountAll();
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<EventAnalytics> {
|
||||
return EventAnalytics.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(eventAnalytics: EventAnalytics): Promise<EventAnalytics> {
|
||||
return EventAnalytics.findOne({ where: eventAnalytics as any });
|
||||
}
|
||||
|
||||
filter(eventAnalytics: EventAnalytics): Promise<EventAnalytics[]> {
|
||||
return EventAnalytics.findAll({ where: eventAnalytics as any });
|
||||
}
|
||||
|
||||
async remove(id: number): Promise<number> {
|
||||
return EventAnalytics.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(eventAnalytics: any, insertIfNotFound: boolean): Promise<EventAnalytics | [affectedCount: number]> {
|
||||
if (eventAnalytics.id) {
|
||||
const existing = await this.findByPk(eventAnalytics.id);
|
||||
if (existing) {
|
||||
return EventAnalytics.update(eventAnalytics, { where: { id: eventAnalytics.id } });
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
return EventAnalytics.create(eventAnalytics as any);
|
||||
}
|
||||
}
|
||||
}
|
||||
290
src/event-category/event-category.controller.ts
Normal file
290
src/event-category/event-category.controller.ts
Normal file
@ -0,0 +1,290 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { EventCategoryService } from './event-category.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
import EventCategory from './event-category.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { EventCategoryDTO, EventCategoryUpdateDTO } from './event-category.dto';
|
||||
|
||||
@ApiTags('eventCategory')
|
||||
@Controller('eventCategory')
|
||||
export class EventCategoryController {
|
||||
constructor(private eventCategoryService: EventCategoryService) {}
|
||||
|
||||
@Get('/all')
|
||||
@ApiOperation({ summary: 'Get all event categories' })
|
||||
@ApiResponse({ status: 200, description: 'Successfully retrieved all event categories' })
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No event categories found',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event categories found'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
async getAll(@Res() res: Response) {
|
||||
const response = await this.eventCategoryService.findAll();
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event categories found'
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
res.send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get event category by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'EventCategory ID' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully retrieved event category by ID',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID is required',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event category not found',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'Event category not found'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
async findById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
|
||||
const response = await this.eventCategoryService.findByPk(id);
|
||||
if (!response) {
|
||||
return res.status(404).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event category with ID ${id} not found`
|
||||
}, null));
|
||||
}
|
||||
|
||||
res.status(200).send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Post('/filter')
|
||||
@ApiOperation({ summary: 'Filter event categories based on criteria' })
|
||||
@ApiBody({ type: EventCategory, description: 'Filter criteria for event categories' })
|
||||
@ApiResponse({ status: 200, description: 'Successfully filtered event categories' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid filter criteria',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_CRITERIA',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No event categories found based on filter criteria',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event categories found based on the filter criteria'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
async filter(@Body() category: EventCategory, @Res() res: Response) {
|
||||
if (!category) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_CRITERIA',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
|
||||
const response = await this.eventCategoryService.filter(category);
|
||||
if (!response) {
|
||||
return res.status(404).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event categories found based on the filter criteria'
|
||||
}, null));
|
||||
}
|
||||
|
||||
res.status(200).send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new event category' })
|
||||
@ApiBody({ type: EventCategoryDTO, description: 'Event category data to insert' })
|
||||
@ApiResponse({ status: 201, description: 'Successfully created an event category' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid event category data',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_DATA',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() category: EventCategoryDTO, @Res() res: Response) {
|
||||
if (!category) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_DATA',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
const response = await this.eventCategoryService.upsert(category, true);
|
||||
res.status(201).send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing event category' })
|
||||
@ApiBody({ type: EventCategoryUpdateDTO, description: 'Event category data to update' })
|
||||
@ApiResponse({ status: 200, description: 'Successfully updated event category' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid data or ID missing',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event category not found',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'Event category not found'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() category: EventCategoryUpdateDTO, @Res() res: Response) {
|
||||
if (!category || !category.id) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
|
||||
const response = await this.eventCategoryService.upsert(category, false);
|
||||
if (!response) {
|
||||
return res.status(404).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event category with ID ${category.id} not found`
|
||||
}, null));
|
||||
}
|
||||
|
||||
res.status(200).send(new GenericResponse(null, response));
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete an event category by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Event category ID to delete' })
|
||||
@ApiResponse({ status: 200, description: 'Successfully deleted event category' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID parameter is required',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event category not found',
|
||||
example: {
|
||||
notification: {
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'Event category not found'
|
||||
},
|
||||
data: null
|
||||
}
|
||||
})
|
||||
async deleteById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
return res.status(400).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null));
|
||||
}
|
||||
|
||||
const response = await this.eventCategoryService.remove(id);
|
||||
if (!response) {
|
||||
return res.status(404).send(new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event category with ID ${id} not found`
|
||||
}, null));
|
||||
}
|
||||
|
||||
res.status(200).send(new GenericResponse(null, response));
|
||||
}
|
||||
}
|
||||
64
src/event-category/event-category.dto.ts
Normal file
64
src/event-category/event-category.dto.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
|
||||
export class EventCategoryDTO {
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
categoryName: 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 EventCategoryUpdateDTO extends EventCategoryDTO {
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
id: number;
|
||||
}
|
||||
46
src/event-category/event-category.entity.ts
Normal file
46
src/event-category/event-category.entity.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { Table, Column, Model, DataType } from 'sequelize-typescript';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
@Table({ tableName: 'event_categories', paranoid: true })
|
||||
export default class EventCategory extends Model {
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'category_name' })
|
||||
categoryName: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'status' })
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validFrom' })
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validTill' })
|
||||
validTill: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'createdAt' })
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'updatedAt' })
|
||||
updatedAt: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'createdBy' })
|
||||
createdBy: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'modifiedBy' })
|
||||
modifiedBy: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'deletedAt' })
|
||||
deletedAt: Date;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'version' })
|
||||
version: number;
|
||||
}
|
||||
11
src/event-category/event-category.module.ts
Normal file
11
src/event-category/event-category.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { EventCategoryController } from './event-category.controller';
|
||||
import { EventCategoryService } from './event-category.service';
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule],
|
||||
providers: [EventCategoryService],
|
||||
controllers: [EventCategoryController],
|
||||
})
|
||||
export class EventCategoryModule {}
|
||||
40
src/event-category/event-category.service.ts
Normal file
40
src/event-category/event-category.service.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import EventCategory from './event-category.entity';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
|
||||
@Injectable()
|
||||
export class EventCategoryService {
|
||||
constructor(private readonly httpService: HttpService) {}
|
||||
|
||||
async findAll(): Promise<{ rows: EventCategory[]; count: number }> {
|
||||
return EventCategory.findAndCountAll();
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<EventCategory> {
|
||||
return EventCategory.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(category: EventCategory): Promise<EventCategory> {
|
||||
return EventCategory.findOne({ where: category as any });
|
||||
}
|
||||
|
||||
filter(category: EventCategory): Promise<EventCategory[]> {
|
||||
return EventCategory.findAll({ where: category as any });
|
||||
}
|
||||
|
||||
async remove(id: number): Promise<number> {
|
||||
return EventCategory.destroy({ where: { id } });
|
||||
}
|
||||
|
||||
async upsert(category: any, insertIfNotFound: boolean): Promise<EventCategory | [affectedCount: number]> {
|
||||
if (category.id) {
|
||||
const existingCategory = await this.findByPk(category.id);
|
||||
if (existingCategory) {
|
||||
return EventCategory.update(category, { where: { id: category.id } });
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
return EventCategory.create(category as any);
|
||||
}
|
||||
}
|
||||
}
|
||||
312
src/event-episodes/event-episodes.controller.ts
Normal file
312
src/event-episodes/event-episodes.controller.ts
Normal file
@ -0,0 +1,312 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { EventEpisodeService } from './event-episodes.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
import EventEpisode from './event-episodes.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { EventEpisodeDTO, EventEpisodeUpdateDTO } from './event-episodes.dto';
|
||||
|
||||
@ApiTags('event-episode')
|
||||
@Controller('event-episode')
|
||||
export class EventEpisodeController {
|
||||
constructor(private eventEpisodeService: EventEpisodeService) {}
|
||||
|
||||
@Get("/all")
|
||||
@ApiOperation({ summary: 'Get all event episodes' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully retrieved all event episodes',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No event episodes found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "No event episodes found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
async getAllEventEpisodes(@Res() res: Response) {
|
||||
const response = await this.eventEpisodeService.findAll() || [];
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event episodes found'
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.send(httpResponse);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get event episode by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Event Episode ID' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID is required',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NO_ID_REQ",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event episode not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Event episode not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully retrieved event episode by ID',
|
||||
})
|
||||
async findById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.eventEpisodeService.findByPk(id) || {};
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event episode with ID ${id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Post('/filter')
|
||||
@ApiOperation({ summary: 'Filter event episodes based on criteria' })
|
||||
@ApiBody({ type: EventEpisode, description: 'Filter criteria for event episodes' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid filter criteria',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_CRITERIA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No event episodes found based on filter criteria',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "No event episodes found based on the filter criteria"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully filtered event episodes',
|
||||
})
|
||||
async filter(@Body() eventEpisode: EventEpisode, @Res() res: Response) {
|
||||
if (!eventEpisode) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_CRITERIA',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.eventEpisodeService.filter(eventEpisode) || [];
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No event episodes found based on the filter criteria'
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new event episode' })
|
||||
@ApiBody({ type: EventEpisodeDTO, description: 'Event episode data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid event episode data',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_DATA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 201,
|
||||
description: 'Successfully created an event episode',
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() eventEpisode: EventEpisodeDTO, @Res() res: Response) {
|
||||
if (!eventEpisode) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_DATA',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.eventEpisodeService.upsert(eventEpisode, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
}
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing event episode' })
|
||||
@ApiBody({ type: EventEpisodeUpdateDTO, description: 'Event episode data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid event episode data or ID missing',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_DATA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event episode not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Event episode not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully updated event episode',
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() eventEpisode: EventEpisodeUpdateDTO, @Res() res: Response) {
|
||||
if (!eventEpisode || !eventEpisode.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.eventEpisodeService.upsert(eventEpisode, false);
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event episode with ID ${eventEpisode.id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete an event episode by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Event episode ID to delete' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID parameter is required',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NO_ID_REQ",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Event episode not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Event episode not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully deleted event episode',
|
||||
})
|
||||
async deleteById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.eventEpisodeService.remove(id) || {};
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Event episode with ID ${id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
}
|
||||
99
src/event-episodes/event-episodes.dto.ts
Normal file
99
src/event-episodes/event-episodes.dto.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
|
||||
export class EventEpisodeDTO {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
episodeName: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
episodeDescription: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
episodeStartDate: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
episodeEndDate: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
episodeLocation: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
episodeType: string;
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
@IsOptional()
|
||||
images: object;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
@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 EventEpisodeUpdateDTO extends EventEpisodeDTO {
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
id: number;
|
||||
}
|
||||
74
src/event-episodes/event-episodes.entity.ts
Normal file
74
src/event-episodes/event-episodes.entity.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { Table, Column, Model, DataType } from 'sequelize-typescript';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
@Table({ tableName: 'event_episodes', paranoid: true })
|
||||
export default class EventEpisode extends Model {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, allowNull: false, field: 'event_id' })
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'episode_name' })
|
||||
episodeName: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'episode_description' })
|
||||
episodeDescription: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'episode_start_date' })
|
||||
episodeStartDate: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'episode_end_date' })
|
||||
episodeEndDate: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'episode_location' })
|
||||
episodeLocation: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'episode_type' })
|
||||
episodeType: string;
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
@Column({ type: DataType.JSON, field: 'images' })
|
||||
images: object;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'status' })
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validFrom' })
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validTill' })
|
||||
validTill: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'createdAt' })
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'updatedAt' })
|
||||
updatedAt: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'createdBy' })
|
||||
createdBy: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'modifiedBy' })
|
||||
modifiedBy: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'deletedAt' })
|
||||
deletedAt: Date;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'version' })
|
||||
version: number;
|
||||
}
|
||||
11
src/event-episodes/event-episodes.module.ts
Normal file
11
src/event-episodes/event-episodes.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { EventEpisodeController } from './event-episodes.controller';
|
||||
import { EventEpisodeService } from './event-episodes.service';
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule],
|
||||
providers: [EventEpisodeService],
|
||||
controllers: [EventEpisodeController],
|
||||
})
|
||||
export class EventEpisodeModule {}
|
||||
41
src/event-episodes/event-episodes.service.ts
Normal file
41
src/event-episodes/event-episodes.service.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import EventEpisode from './event-episodes.entity';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
|
||||
@Injectable()
|
||||
export class EventEpisodeService {
|
||||
constructor(private readonly httpService: HttpService) { }
|
||||
|
||||
async findAll(): Promise<{ rows: EventEpisode[], count: number }> {
|
||||
return EventEpisode.findAndCountAll();
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<EventEpisode> {
|
||||
return EventEpisode.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(eventEpisode: EventEpisode): Promise<EventEpisode> {
|
||||
return EventEpisode.findOne({ where: eventEpisode as any });
|
||||
}
|
||||
|
||||
filter(eventEpisode: EventEpisode): Promise<EventEpisode[]> {
|
||||
return EventEpisode.findAll({ where: eventEpisode as any });
|
||||
}
|
||||
|
||||
async remove(id: number): Promise<number> {
|
||||
return EventEpisode.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(eventEpisode: any, insertIfNotFound: boolean): Promise<EventEpisode | [affectedCount: number]> {
|
||||
if (eventEpisode.id) {
|
||||
const existingEventEpisode = await this.findByPk(eventEpisode.id);
|
||||
if (existingEventEpisode) {
|
||||
return EventEpisode.update(eventEpisode, { where: { id: eventEpisode.id } });
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
return EventEpisode.create(eventEpisode as any);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,18 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UploadedFile, UploadedFiles, UseInterceptors, UsePipes, ValidationPipe } 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';
|
||||
import { EventDTO, EventUpdateDTO } from './event.dto';
|
||||
|
||||
@ApiTags('event')
|
||||
@Controller('event')
|
||||
export class EventController {
|
||||
constructor(private eventService: EventService) {}
|
||||
constructor(private eventService: EventService) { }
|
||||
|
||||
@Get("/all")
|
||||
@ApiOperation({ summary: 'Get all events' })
|
||||
@ -31,7 +35,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 +182,34 @@ 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);
|
||||
}
|
||||
})
|
||||
}))
|
||||
@UsePipes(new ValidationPipe({ whitelist: true , skipMissingProperties: true }))
|
||||
async insert(@Body() body: EventDTO, @Res() res: Response, @UploadedFiles() files?: Express.Multer.File[]) {
|
||||
// const event = JSON.parse(body)
|
||||
// console.log(body);
|
||||
// if (!files) {
|
||||
// console.log("No files");
|
||||
// }
|
||||
if (!body.organizer_id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.MISSING_ORGANIZER_ID',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
// console.log(files);
|
||||
if (!body || !files) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
@ -188,8 +218,13 @@ export class EventController {
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
delete event.id;
|
||||
const response = await this.eventService.upsert(event, true);
|
||||
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);
|
||||
body.images = {
|
||||
images: imageFiles,
|
||||
videos: videoFiles,
|
||||
};
|
||||
const response = await this.eventService.upsert(body, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
}
|
||||
@ -227,7 +262,8 @@ export class EventController {
|
||||
status: 200,
|
||||
description: 'Successfully updated event',
|
||||
})
|
||||
async update(@Body() event: Event, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() event: EventUpdateDTO, @Res() res: Response) {
|
||||
if (!event || !event.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
|
||||
120
src/event/event.dto.ts
Normal file
120
src/event/event.dto.ts
Normal file
@ -0,0 +1,120 @@
|
||||
import { IsString, IsNumber, IsDate, IsOptional, IsObject } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
|
||||
export class EventDTO {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
organizer_id: number;
|
||||
|
||||
@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;
|
||||
}
|
||||
@ -4,9 +4,9 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
@Table({ tableName: 'events', paranoid: true })
|
||||
export default class Event extends Model {
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'org_email' })
|
||||
orgEmail: string;
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'organizer_id' })
|
||||
organizerId: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'event_name' })
|
||||
|
||||
@ -13,11 +13,7 @@ export class EventService {
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<Event> {
|
||||
|
||||
const event = Event.findByPk(id,)
|
||||
// //const textbookExists = await this.checkTextbookExists((await event).textbookId);
|
||||
|
||||
return event
|
||||
return Event.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(event: Event): Promise<Event> {
|
||||
@ -32,7 +28,7 @@ export class EventService {
|
||||
return Event.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(event: Event, insertIfNotFound: boolean): Promise<Event | [affectedCount: number]> {
|
||||
async upsert(event: any, insertIfNotFound: boolean): Promise<Event | [affectedCount: number]> {
|
||||
if (event.id) {
|
||||
const existingEvent = await this.findByPk(event.id);
|
||||
if (existingEvent) {
|
||||
@ -40,8 +36,6 @@ export class EventService {
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
//const textbookExists = await this.checkTextbookExists(event.textbookId);
|
||||
|
||||
return Event.create(event as any)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { EventAdditionalDetailService } from './eventAdditionalDetail.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../../common/GenericResponse.model';
|
||||
import EventAdditionalDetail from './eventAdditionalDetail.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { EventAdditionalDetailDTO, EventAdditionalDetailUpdateDTO } from './eventAdditionalDetail.dto';
|
||||
|
||||
@ApiTags('event/addl')
|
||||
@Controller('event/addl/')
|
||||
@ -160,7 +161,7 @@ export class EventAdditionalDetailController {
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new eventAdditionalDetail' })
|
||||
@ApiBody({ type: EventAdditionalDetail, description: 'EventAdditionalDetail data to insert' })
|
||||
@ApiBody({ type: EventAdditionalDetailDTO, description: 'EventAdditionalDetail data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid eventAdditionalDetail data',
|
||||
@ -178,7 +179,8 @@ export class EventAdditionalDetailController {
|
||||
status: 201,
|
||||
description: 'Successfully created a eventAdditionalDetail',
|
||||
})
|
||||
async insert(@Body() eventAdditionalDetail: EventAdditionalDetail, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() eventAdditionalDetail: EventAdditionalDetailDTO, @Res() res: Response) {
|
||||
if (!eventAdditionalDetail) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
@ -188,7 +190,6 @@ export class EventAdditionalDetailController {
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
delete eventAdditionalDetail.id;
|
||||
const response = await this.eventAdditionalDetailService.upsert(eventAdditionalDetail, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
@ -196,7 +197,7 @@ export class EventAdditionalDetailController {
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing eventAdditionalDetail' })
|
||||
@ApiBody({ type: EventAdditionalDetail, description: 'EventAdditionalDetail data to update' })
|
||||
@ApiBody({ type: EventAdditionalDetailUpdateDTO, description: 'EventAdditionalDetail data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid eventAdditionalDetail data or ID missing',
|
||||
@ -227,7 +228,8 @@ export class EventAdditionalDetailController {
|
||||
status: 200,
|
||||
description: 'Successfully updated eventAdditionalDetail',
|
||||
})
|
||||
async update(@Body() eventAdditionalDetail: EventAdditionalDetail, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() eventAdditionalDetail: EventAdditionalDetailUpdateDTO, @Res() res: Response) {
|
||||
if (!eventAdditionalDetail || !eventAdditionalDetail.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
|
||||
66
src/event/eventAdditionalDetail/eventAdditionalDetail.dto.ts
Normal file
66
src/event/eventAdditionalDetail/eventAdditionalDetail.dto.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { IsString, IsNumber, IsDate, IsOptional } 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;
|
||||
}
|
||||
@ -15,8 +15,6 @@ export class EventAdditionalDetailService {
|
||||
async findByPk(id: number): Promise<EventAdditionalDetail> {
|
||||
|
||||
const eventAdditionalDetail = EventAdditionalDetail.findByPk(id,)
|
||||
// //const textbookExists = await this.checkTextbookExists((await eventAdditionalDetail).textbookId);
|
||||
|
||||
return eventAdditionalDetail
|
||||
}
|
||||
|
||||
@ -32,7 +30,7 @@ export class EventAdditionalDetailService {
|
||||
return EventAdditionalDetail.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(eventAdditionalDetail: EventAdditionalDetail, insertIfNotFound: boolean): Promise<EventAdditionalDetail | [affectedCount: number]> {
|
||||
async upsert(eventAdditionalDetail: any, insertIfNotFound: boolean): Promise<EventAdditionalDetail | [affectedCount: number]> {
|
||||
if (eventAdditionalDetail.id) {
|
||||
const existingEventAdditionalDetail = await this.findByPk(eventAdditionalDetail.id);
|
||||
if (existingEventAdditionalDetail) {
|
||||
@ -40,8 +38,6 @@ export class EventAdditionalDetailService {
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
//const textbookExists = await this.checkTextbookExists(eventAdditionalDetail.textbookId);
|
||||
|
||||
return EventAdditionalDetail.create(eventAdditionalDetail as any)
|
||||
}
|
||||
}
|
||||
|
||||
12
src/google-oauth/google-oauth.guard.ts
Normal file
12
src/google-oauth/google-oauth.guard.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { AuthGuard } from "@nestjs/passport";
|
||||
|
||||
@Injectable()
|
||||
export class GoogleOauthGuard extends AuthGuard('google') {
|
||||
constructor() {
|
||||
super({
|
||||
// accessType: 'offline',
|
||||
});
|
||||
}
|
||||
}
|
||||
30
src/google-oauth/google.strategy.ts
Normal file
30
src/google-oauth/google.strategy.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { PassportStrategy } from "@nestjs/passport";
|
||||
import { Strategy, VerifyCallback } from "passport-google-oauth20";
|
||||
import { Utility } from "src/common/Utility";
|
||||
|
||||
@Injectable()
|
||||
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
clientID: Utility.googleOauthConfig.clientId,
|
||||
clientSecret: Utility.googleOauthConfig.clientSecret,
|
||||
callbackURL: Utility.googleOauthConfig.callbackURL,
|
||||
scope: Utility.googleOauthConfig.scope,
|
||||
});
|
||||
}
|
||||
|
||||
async validate(accessToken: string, refreshToken: string, profile: any, done: VerifyCallback) {
|
||||
|
||||
const { name, emails } = profile;
|
||||
const user = {
|
||||
email: emails[0].value,
|
||||
name: name.givenName,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
};
|
||||
console.log("user object in validate is", user)
|
||||
done(null, user);
|
||||
}
|
||||
}
|
||||
@ -11,4 +11,8 @@ export default class RefreshToken extends Model {
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT })
|
||||
token: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT })
|
||||
type: string;
|
||||
}
|
||||
|
||||
30
src/locations/dto/create-location.dto.ts
Normal file
30
src/locations/dto/create-location.dto.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateLocationDto {
|
||||
@ApiProperty()
|
||||
name: string;
|
||||
|
||||
@ApiProperty()
|
||||
code: string;
|
||||
|
||||
@ApiProperty({ type: [String], required: false })
|
||||
images?: string[];
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
status?: string;
|
||||
|
||||
@ApiProperty({ required: false, type: String, format: 'date' })
|
||||
validFrom?: Date;
|
||||
|
||||
@ApiProperty({ required: false, type: String, format: 'date' })
|
||||
validTill?: Date;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
createdBy?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
modifiedBy?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
version?: number;
|
||||
}
|
||||
7
src/locations/dto/update-location.dto.ts
Normal file
7
src/locations/dto/update-location.dto.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { PartialType, ApiProperty } from '@nestjs/swagger';
|
||||
import { CreateLocationDto } from './create-location.dto';
|
||||
|
||||
export class UpdateLocationDto extends PartialType(CreateLocationDto) {
|
||||
@ApiProperty()
|
||||
id: number;
|
||||
}
|
||||
67
src/locations/entities/location.entity.ts
Normal file
67
src/locations/entities/location.entity.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import {
|
||||
Table,
|
||||
Column,
|
||||
Model,
|
||||
DataType,
|
||||
PrimaryKey,
|
||||
AutoIncrement,
|
||||
Default,
|
||||
} from 'sequelize-typescript';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
@Table({ tableName: 'locations' })
|
||||
export class Location extends Model {
|
||||
@ApiProperty({ type: Number })
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column({ type: DataType.BIGINT })
|
||||
id: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT })
|
||||
name: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT })
|
||||
code: string;
|
||||
|
||||
@ApiProperty({ type: [String] })
|
||||
@Column({ type: DataType.ARRAY(DataType.TEXT) })
|
||||
images: string[];
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT })
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY })
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY })
|
||||
validTill: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE })
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE })
|
||||
updatedAt: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT })
|
||||
createdBy: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT })
|
||||
modifiedBy: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE })
|
||||
deletedAt: Date;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER })
|
||||
version: number;
|
||||
}
|
||||
20
src/locations/locations.controller.spec.ts
Normal file
20
src/locations/locations.controller.spec.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { LocationsController } from './locations.controller';
|
||||
import { LocationsService } from './locations.service';
|
||||
|
||||
describe('LocationsController', () => {
|
||||
let controller: LocationsController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [LocationsController],
|
||||
providers: [LocationsService],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<LocationsController>(LocationsController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
41
src/locations/locations.controller.ts
Normal file
41
src/locations/locations.controller.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Controller, Get, Post, Body, Patch, Param, Delete, Query } from '@nestjs/common';
|
||||
import { LocationsService } from './locations.service';
|
||||
import { CreateLocationDto } from './dto/create-location.dto';
|
||||
import { UpdateLocationDto } from './dto/update-location.dto';
|
||||
|
||||
@Controller('locations')
|
||||
export class LocationsController {
|
||||
constructor(private readonly locationsService: LocationsService) { }
|
||||
|
||||
@Post()
|
||||
create(@Body() createLocationDto: CreateLocationDto) {
|
||||
return this.locationsService.create(createLocationDto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.locationsService.findAll();
|
||||
}
|
||||
|
||||
@Get('search')
|
||||
async search(@Query('q') query: string) {
|
||||
return this.locationsService.search(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.locationsService.findOne(+id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
update(@Param('id') id: string, @Body() updateLocationDto: UpdateLocationDto) {
|
||||
return this.locationsService.update(+id, updateLocationDto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.locationsService.remove(+id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
9
src/locations/locations.module.ts
Normal file
9
src/locations/locations.module.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LocationsService } from './locations.service';
|
||||
import { LocationsController } from './locations.controller';
|
||||
|
||||
@Module({
|
||||
controllers: [LocationsController],
|
||||
providers: [LocationsService],
|
||||
})
|
||||
export class LocationsModule {}
|
||||
18
src/locations/locations.service.spec.ts
Normal file
18
src/locations/locations.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { LocationsService } from './locations.service';
|
||||
|
||||
describe('LocationsService', () => {
|
||||
let service: LocationsService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [LocationsService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<LocationsService>(LocationsService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
56
src/locations/locations.service.ts
Normal file
56
src/locations/locations.service.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { CreateLocationDto } from './dto/create-location.dto';
|
||||
import { UpdateLocationDto } from './dto/update-location.dto';
|
||||
import { Location } from './entities/location.entity';
|
||||
import { Op } from 'sequelize';
|
||||
|
||||
@Injectable()
|
||||
export class LocationsService {
|
||||
async create(createLocationDto: CreateLocationDto) {
|
||||
return await Location.create(createLocationDto as any);
|
||||
}
|
||||
|
||||
async findAll() {
|
||||
return await Location.findAll();
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
const location = await Location.findByPk(id);
|
||||
if (!location) {
|
||||
throw new NotFoundException(`Location with ID ${id} not found`);
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
async update(id: number, updateLocationDto: UpdateLocationDto) {
|
||||
const location = await Location.findByPk(id);
|
||||
if (!location) {
|
||||
throw new NotFoundException(`Location with ID ${id} not found`);
|
||||
}
|
||||
await location.update(updateLocationDto);
|
||||
return location;
|
||||
}
|
||||
|
||||
async remove(id: number) {
|
||||
const location = await Location.findByPk(id);
|
||||
if (!location) {
|
||||
throw new NotFoundException(`Location with ID ${id} not found`);
|
||||
}
|
||||
await location.destroy();
|
||||
return { message: `Location with ID ${id} has been deleted.` };
|
||||
}
|
||||
|
||||
async search(q: string) {
|
||||
if (!q) return []; // no query, return empty list or all
|
||||
|
||||
const locations = await Location.findAll({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ name: { [Op.iLike]: `%${q}%` } },
|
||||
{ code: { [Op.iLike]: `%${q}%` } }
|
||||
],
|
||||
},
|
||||
});
|
||||
return locations;
|
||||
}
|
||||
}
|
||||
17
src/mail/mail.controller.ts
Normal file
17
src/mail/mail.controller.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { MailService } from './mail.service';
|
||||
|
||||
@Controller('mail')
|
||||
export class MailController {
|
||||
constructor(private readonly mailService: MailService) {}
|
||||
|
||||
@Post()
|
||||
async sendTestEmail(@Body() body: { email: string }) {
|
||||
const { email } = body;
|
||||
return this.mailService.sendMail(
|
||||
email,
|
||||
'Test Email',
|
||||
'This is a test email.',
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ import { Module } from '@nestjs/common';
|
||||
import { MailService } from './mail.service';
|
||||
import { join } from 'path';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
import { MailController } from './mail.controller';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -23,5 +24,6 @@ import { Utility } from 'src/common/Utility';
|
||||
],
|
||||
providers: [MailService],
|
||||
exports: [MailService], // 👈 export for DI
|
||||
controllers: [MailController],
|
||||
})
|
||||
export class MailModule {}
|
||||
export class MailModule { }
|
||||
|
||||
@ -1,19 +1,25 @@
|
||||
// import { MailerService } from '@nestjs-modules/mailer'/;
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import * as nodemailer from 'nodemailer';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
|
||||
@Injectable()
|
||||
export class MailService {
|
||||
// constructor(private mailerService: MailerService) { }
|
||||
private transporter: nodemailer.Transporter;
|
||||
|
||||
constructor() {
|
||||
this.transporter = nodemailer.createTransport(Utility.mailConfig.transport);
|
||||
}
|
||||
|
||||
// async sendEmail(templateName: string, subject: string, context: any, toEmail: string, ccEmails?: string[], bccEmails?: string[]) {
|
||||
// await this.mailerService.sendMail({
|
||||
// to: toEmail,
|
||||
// cc: ccEmails,
|
||||
// bcc: bccEmails,
|
||||
// subject: subject,
|
||||
// template: templateName, // `.hbs` extension is appended automatically
|
||||
// context,
|
||||
// })
|
||||
// }
|
||||
async sendMail(to: string, subject: string, text: string, html?: string) {
|
||||
const info = await this.transporter.sendMail({
|
||||
from: Utility.mailConfig.defaults.from,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
html,
|
||||
});
|
||||
|
||||
console.log('Email sent:', info.messageId);
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
12
src/main.ts
12
src/main.ts
@ -4,6 +4,8 @@ import * as bodyParser from 'body-parser';
|
||||
import * as configMaster from './app-config/config.json';
|
||||
import { Utility } from './common/Utility';
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
import * as cookieParser from 'cookie-parser';
|
||||
|
||||
|
||||
async function bootstrap() {
|
||||
Utility.appPort = configMaster.local.appConfig.port;
|
||||
@ -11,6 +13,8 @@ async function bootstrap() {
|
||||
Utility.fileConfig = configMaster.local.fileConfig;
|
||||
Utility.swaggerConfig = configMaster.local.swaggerConfig;
|
||||
Utility.vapidConfig = configMaster.local.vapidConfig;
|
||||
Utility.redisConfig = configMaster.local.redisConfig;
|
||||
Utility.googleOauthConfig = configMaster.local.googleOauthConfig;
|
||||
|
||||
const app = await NestFactory.create(AppModule, { cors: true });
|
||||
|
||||
@ -23,6 +27,14 @@ async function bootstrap() {
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
SwaggerModule.setup('api', app, document);
|
||||
|
||||
app.enableCors(
|
||||
{
|
||||
origin: true,
|
||||
credentials: true,
|
||||
}
|
||||
);
|
||||
app.use(cookieParser());
|
||||
|
||||
app.use(bodyParser.json({ limit: '50mb' }));
|
||||
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
|
||||
await app.listen(Utility.appPort);
|
||||
|
||||
@ -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,17 @@ 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) {
|
||||
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 +228,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,
|
||||
|
||||
88
src/payout/payout.dto.ts
Normal file
88
src/payout/payout.dto.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty, IsEnum } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
|
||||
export class PayoutDTO {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
payeeId: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
amount: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
paymentMethod: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
transactionId: string;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNotEmpty()
|
||||
@IsNumber()
|
||||
paidToId: number;
|
||||
|
||||
@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
|
||||
}
|
||||
@ -4,9 +4,9 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
@Table({ tableName: 'payouts', paranoid: true })
|
||||
export default class Payout extends Model {
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'payee_email' })
|
||||
payeeEmail: string;
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'payee_id' })
|
||||
payeeId: number;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'amount' })
|
||||
@ -21,8 +21,8 @@ export default class Payout extends Model {
|
||||
transactionId: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'paid_to_email' })
|
||||
paidToEmail: string;
|
||||
@Column({ type: DataType.TEXT, field: 'paid_to_id' })
|
||||
paidToId: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'payout_date' })
|
||||
|
||||
@ -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 {
|
||||
@ -13,11 +14,7 @@ export class PayoutService {
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<Payout> {
|
||||
|
||||
const payout = Payout.findByPk(id,)
|
||||
// //const textbookExists = await this.checkTextbookExists((await payout).textbookId);
|
||||
|
||||
return payout
|
||||
return Payout.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(payout: Payout): Promise<Payout> {
|
||||
@ -32,7 +29,7 @@ export class PayoutService {
|
||||
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) {
|
||||
const existingPayout = await this.findByPk(payout.id);
|
||||
if (existingPayout) {
|
||||
@ -40,8 +37,6 @@ export class PayoutService {
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
//const textbookExists = await this.checkTextbookExists(payout.textbookId);
|
||||
|
||||
return Payout.create(payout as any)
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ export class PolicyService {
|
||||
return Policy.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(policy: Policy, insertIfNotFound: boolean): Promise<Policy | [affectedCount: number]> {
|
||||
async upsert(policy: any, insertIfNotFound: boolean): Promise<Policy | [affectedCount: number]> {
|
||||
if (policy.id) {
|
||||
const existingPolicy = await this.findByPk(policy.id);
|
||||
if (existingPolicy) {
|
||||
|
||||
312
src/promotions/promotions.controller.ts
Normal file
312
src/promotions/promotions.controller.ts
Normal file
@ -0,0 +1,312 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { PromotionService } from './promotions.service'; // Updated service
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
import Promotion from './promotions.entity'; // Updated entity
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { PromotionDTO, PromotionUpdateDTO } from './promotions.dto';
|
||||
|
||||
@ApiTags('promotion')
|
||||
@Controller('promotion')
|
||||
export class PromotionController {
|
||||
constructor(private promotionService: PromotionService) {}
|
||||
|
||||
@Get("/all")
|
||||
@ApiOperation({ summary: 'Get all promotions' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully retrieved all promotions',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No promotions found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "No promotions found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
async getAllPromotions(@Res() res: Response) {
|
||||
const response = await this.promotionService.findAll() || [];
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No promotions found'
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.send(httpResponse);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get promotion by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Promotion ID' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID is required',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NO_ID_REQ",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Promotion not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Promotion not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully retrieved promotion by ID',
|
||||
})
|
||||
async findById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.promotionService.findByPk(id) || {};
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Promotion with ID ${id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Post('/filter')
|
||||
@ApiOperation({ summary: 'Filter promotions based on criteria' })
|
||||
@ApiBody({ type: Promotion, description: 'Filter criteria for promotions' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid filter criteria',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_CRITERIA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'No promotions found based on filter criteria',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "No promotions found based on the filter criteria"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully filtered promotions',
|
||||
})
|
||||
async filter(@Body() promotion: Promotion, @Res() res: Response) {
|
||||
if (!promotion) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_CRITERIA',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.promotionService.filter(promotion) || [];
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: 'No promotions found based on the filter criteria'
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new promotion' })
|
||||
@ApiBody({ type: PromotionDTO, description: 'Promotion data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid promotion data',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_DATA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 201,
|
||||
description: 'Successfully created a promotion',
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() promotion: PromotionDTO, @Res() res: Response) {
|
||||
if (!promotion) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.INVALID_DATA',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.promotionService.upsert(promotion, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
}
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing promotion' })
|
||||
@ApiBody({ type: PromotionUpdateDTO, description: 'Promotion data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid promotion data or ID missing',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.INVALID_DATA",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Promotion not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Promotion not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully updated promotion',
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() promotion: PromotionUpdateDTO, @Res() res: Response) {
|
||||
if (!promotion || !promotion.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.promotionService.upsert(promotion, false);
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Promotion with ID ${promotion.id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete a promotion by ID' })
|
||||
@ApiParam({ name: 'id', type: Number, description: 'Promotion ID to delete' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'ID parameter is required',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NO_ID_REQ",
|
||||
"stackTrace": "Request"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Promotion not found',
|
||||
example: {
|
||||
"notification": {
|
||||
"exception": true,
|
||||
"exceptionSeverity": "HIGH",
|
||||
"exceptionMessage": "ERR.NOT_FOUND",
|
||||
"stackTrace": "Promotion not found"
|
||||
},
|
||||
"data": null
|
||||
}
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Successfully deleted promotion',
|
||||
})
|
||||
async deleteById(@Param('id') id: number, @Res() res: Response) {
|
||||
if (!id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NO_ID_REQ',
|
||||
stackTrace: 'Request'
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
const response = await this.promotionService.remove(id) || {};
|
||||
if (!response) {
|
||||
const errorResponse = new GenericResponse({
|
||||
exception: true,
|
||||
exceptionSeverity: 'HIGH',
|
||||
exceptionMessage: 'ERR.NOT_FOUND',
|
||||
stackTrace: `Promotion with ID ${id} not found`
|
||||
}, null);
|
||||
return res.status(404).send(errorResponse);
|
||||
}
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(200).send(httpResponse);
|
||||
}
|
||||
}
|
||||
91
src/promotions/promotions.dto.ts
Normal file
91
src/promotions/promotions.dto.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { IsString, IsNumber, IsDate, IsOptional, IsNotEmpty } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
|
||||
export class PromotionDTO {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsDate()
|
||||
@IsNotEmpty()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
startDate: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@IsDate()
|
||||
@IsNotEmpty()
|
||||
@Transform(({ value }) => new Date(value))
|
||||
endDate: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
location: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
type: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
description: 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 PromotionUpdateDTO extends PromotionDTO {
|
||||
@ApiProperty({ type: Number })
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
id: number
|
||||
}
|
||||
66
src/promotions/promotions.entity.ts
Normal file
66
src/promotions/promotions.entity.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { Table, Column, Model, DataType } from 'sequelize-typescript';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
@Table({ tableName: 'promotions', paranoid: true })
|
||||
export default class Promotion extends Model {
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, allowNull: false, field: 'event_id' })
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'start_date' })
|
||||
startDate: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'end_date' })
|
||||
endDate: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'location' })
|
||||
location: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'type' })
|
||||
type: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'description' })
|
||||
description: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'status' })
|
||||
status: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validFrom' })
|
||||
validFrom: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATEONLY, field: 'validTill' })
|
||||
validTill: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'createdAt' })
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'updatedAt' })
|
||||
updatedAt: Date;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'createdBy' })
|
||||
createdBy: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'modifiedBy' })
|
||||
modifiedBy: string;
|
||||
|
||||
@ApiProperty({ type: Date })
|
||||
@Column({ type: DataType.DATE, field: 'deletedAt' })
|
||||
deletedAt: Date;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'version' })
|
||||
version: number;
|
||||
}
|
||||
11
src/promotions/promotions.module.ts
Normal file
11
src/promotions/promotions.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { PromotionController } from './promotions.controller';
|
||||
import { PromotionService } from './promotions.service';
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule],
|
||||
providers: [PromotionService],
|
||||
controllers: [PromotionController],
|
||||
})
|
||||
export class PromotionModule { }
|
||||
41
src/promotions/promotions.service.ts
Normal file
41
src/promotions/promotions.service.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import Promotion from './promotions.entity';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
|
||||
@Injectable()
|
||||
export class PromotionService {
|
||||
constructor(private readonly httpService: HttpService) { }
|
||||
|
||||
async findAll(): Promise<{ rows: Promotion[], count: number }> {
|
||||
return Promotion.findAndCountAll();
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<Promotion> {
|
||||
return Promotion.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(promotion: Promotion): Promise<Promotion> {
|
||||
return Promotion.findOne({ where: promotion as any });
|
||||
}
|
||||
|
||||
filter(promotion: Promotion): Promise<Promotion[]> {
|
||||
return Promotion.findAll({ where: promotion as any });
|
||||
}
|
||||
|
||||
async remove(id: number): Promise<number> {
|
||||
return Promotion.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(promotion: any, insertIfNotFound: boolean): Promise<Promotion | [affectedCount: number]> {
|
||||
if (promotion.id) {
|
||||
const existingPromotion = await this.findByPk(promotion.id);
|
||||
if (existingPromotion) {
|
||||
return Promotion.update(promotion, { where: { id: promotion.id } });
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
return Promotion.create(promotion as any);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { PushSubscriptionController } from './push-subscription.controller';
|
||||
|
||||
describe('PushSubscriptionController', () => {
|
||||
let controller: PushSubscriptionController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [PushSubscriptionController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<PushSubscriptionController>(PushSubscriptionController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
@ -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';
|
||||
}
|
||||
|
||||
@ -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)
|
||||
await webPush.sendNotification(pushSub, payload);
|
||||
} catch (err) {
|
||||
console.log("error occurred", err)
|
||||
console.error('Error sending push notification', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/redis/redis.controller.ts
Normal file
66
src/redis/redis.controller.ts
Normal file
@ -0,0 +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 {
|
||||
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 && body.ttl <= 0) {
|
||||
throw new BadRequestException('TTL must be a positive number');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@Get('get/:key')
|
||||
async getValue(@Param('key') key: string) {
|
||||
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) {
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@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');
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/redis/redis.module.ts
Normal file
11
src/redis/redis.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { RedisProvider } from './redis.provider';
|
||||
import { RedisController } from './redis.controller';
|
||||
import { RedisService } from './redis.service';
|
||||
|
||||
@Module({
|
||||
controllers: [RedisController],
|
||||
providers: [RedisService, RedisProvider],
|
||||
exports: [RedisProvider, RedisService],
|
||||
})
|
||||
export class RedisModule { }
|
||||
27
src/redis/redis.provider.ts
Normal file
27
src/redis/redis.provider.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Injectable, Global } from '@nestjs/common';
|
||||
import Redis from 'ioredis';
|
||||
import { Utility } from 'src/common/Utility';
|
||||
|
||||
@Global()
|
||||
@Injectable()
|
||||
export class RedisProvider {
|
||||
private redisClient: Redis;
|
||||
|
||||
constructor() {
|
||||
this.redisClient = new Redis({
|
||||
host: Utility.redisConfig.host,
|
||||
port: Utility.redisConfig.port,
|
||||
db: Utility.redisConfig.db,
|
||||
username: Utility.redisConfig.username || 'default', // For Redis >= 6 with ACLs
|
||||
password: Utility.redisConfig.password
|
||||
|
||||
});
|
||||
|
||||
this.redisClient.on('connect', () => console.log('connected to redis'));
|
||||
this.redisClient.on('error', (err) => console.error('error:', err));
|
||||
}
|
||||
|
||||
get client() {
|
||||
return this.redisClient;
|
||||
}
|
||||
}
|
||||
32
src/redis/redis.service.ts
Normal file
32
src/redis/redis.service.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { RedisProvider } from './redis.provider';
|
||||
|
||||
@Injectable()
|
||||
export class RedisService {
|
||||
constructor(private readonly redisProvider: RedisProvider) {}
|
||||
|
||||
async set(key: string, value: any): Promise<void> {
|
||||
const client = this.redisProvider.client;
|
||||
await client.set(key, value, );
|
||||
}
|
||||
|
||||
async del(key: string): Promise<void> {
|
||||
const client = this.redisProvider.client;
|
||||
await client.del(key);
|
||||
}
|
||||
|
||||
async flushall(): Promise<void> {
|
||||
const client = this.redisProvider.client;
|
||||
await client.flushall();
|
||||
}
|
||||
|
||||
async setTimed(key: string, value: any, ttl: number): Promise<void> {
|
||||
const client = this.redisProvider.client;
|
||||
await client.set(key, value, 'EX', ttl);
|
||||
}
|
||||
|
||||
async get(key: string): Promise<string> {
|
||||
const client = this.redisProvider.client;
|
||||
return client.get(key);
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,10 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { RefundService } from './refund.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
import Refund from './refund.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { RefundDTO, RefundUpdateDTO } from './refund.dto';
|
||||
|
||||
@ApiTags('refund')
|
||||
@Controller('refund')
|
||||
@ -160,7 +161,7 @@ export class RefundController {
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new refund' })
|
||||
@ApiBody({ type: Refund, description: 'Refund data to insert' })
|
||||
@ApiBody({ type: RefundDTO, description: 'Refund data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid refund data',
|
||||
@ -178,7 +179,8 @@ export class RefundController {
|
||||
status: 201,
|
||||
description: 'Successfully created a refund',
|
||||
})
|
||||
async insert(@Body() refund: Refund, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() refund: RefundDTO, @Res() res: Response) {
|
||||
if (!refund) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
@ -188,7 +190,6 @@ export class RefundController {
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
delete refund.id;
|
||||
const response = await this.refundService.upsert(refund, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
@ -196,7 +197,7 @@ export class RefundController {
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing refund' })
|
||||
@ApiBody({ type: Refund, description: 'Refund data to update' })
|
||||
@ApiBody({ type: RefundUpdateDTO, description: 'Refund data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid refund data or ID missing',
|
||||
@ -227,7 +228,8 @@ export class RefundController {
|
||||
status: 200,
|
||||
description: 'Successfully updated refund',
|
||||
})
|
||||
async update(@Body() refund: Refund, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() refund: RefundUpdateDTO, @Res() res: Response) {
|
||||
if (!refund || !refund.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
|
||||
83
src/refund/refund.dto.ts
Normal file
83
src/refund/refund.dto.ts
Normal 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
|
||||
}
|
||||
@ -13,11 +13,7 @@ export class RefundService {
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<Refund> {
|
||||
|
||||
const refund = Refund.findByPk(id,)
|
||||
// //const textbookExists = await this.checkTextbookExists((await refund).textbookId);
|
||||
|
||||
return refund
|
||||
return Refund.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(refund: Refund): Promise<Refund> {
|
||||
@ -32,7 +28,7 @@ export class RefundService {
|
||||
return Refund.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(refund: Refund, insertIfNotFound: boolean): Promise<Refund | [affectedCount: number]> {
|
||||
async upsert(refund: any, insertIfNotFound: boolean): Promise<Refund | [affectedCount: number]> {
|
||||
if (refund.id) {
|
||||
const existingRefund = await this.findByPk(refund.id);
|
||||
if (existingRefund) {
|
||||
@ -40,8 +36,6 @@ export class RefundService {
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
//const textbookExists = await this.checkTextbookExists(refund.textbookId);
|
||||
|
||||
return Refund.create(refund as any)
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ export class ResourcesService {
|
||||
return Resources.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(resources: Resources, insertIfNotFound: boolean): Promise<Resources | [affectedCount: number]> {
|
||||
async upsert(resources: any, insertIfNotFound: boolean): Promise<Resources | [affectedCount: number]> {
|
||||
if (resources.id) {
|
||||
const existingResources = await this.findByPk(resources.id);
|
||||
if (existingResources) {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { ReviewService } from './review.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
import Review from './review.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { ReviewDTO, ReviewUpdateDTO } from './review.dto';
|
||||
|
||||
@ApiTags('review')
|
||||
@Controller('review')
|
||||
@ -160,7 +161,7 @@ export class ReviewController {
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new review' })
|
||||
@ApiBody({ type: Review, description: 'Review data to insert' })
|
||||
@ApiBody({ type: ReviewDTO, description: 'Review data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid review data',
|
||||
@ -178,7 +179,8 @@ export class ReviewController {
|
||||
status: 201,
|
||||
description: 'Successfully created a review',
|
||||
})
|
||||
async insert(@Body() review: Review, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() review: ReviewDTO, @Res() res: Response) {
|
||||
if (!review) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
@ -188,7 +190,6 @@ export class ReviewController {
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
delete review.id;
|
||||
const response = await this.reviewService.upsert(review, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
@ -196,7 +197,7 @@ export class ReviewController {
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing review' })
|
||||
@ApiBody({ type: Review, description: 'Review data to update' })
|
||||
@ApiBody({ type: ReviewUpdateDTO, description: 'Review data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid review data or ID missing',
|
||||
@ -227,7 +228,8 @@ export class ReviewController {
|
||||
status: 200,
|
||||
description: 'Successfully updated review',
|
||||
})
|
||||
async update(@Body() review: Review, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() review: ReviewUpdateDTO, @Res() res: Response) {
|
||||
if (!review || !review.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
|
||||
79
src/review/review.dto.ts
Normal file
79
src/review/review.dto.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { IsString, IsNumber, IsDate, IsNotEmpty, IsOptional } 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: Number })
|
||||
@IsNotEmpty()
|
||||
@IsNumber()
|
||||
buyerId: number;
|
||||
|
||||
@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;
|
||||
}
|
||||
@ -9,8 +9,8 @@ export default class Review extends Model {
|
||||
eventId: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'buyer_email' })
|
||||
buyerEmail: string;
|
||||
@Column({ type: DataType.TEXT, field: 'buyer_id' })
|
||||
buyerId: string;
|
||||
|
||||
@ApiProperty({ type: Number })
|
||||
@Column({ type: DataType.NUMBER, field: 'rating' })
|
||||
|
||||
@ -13,11 +13,7 @@ export class ReviewService {
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<Review> {
|
||||
|
||||
const review = Review.findByPk(id,)
|
||||
// //const textbookExists = await this.checkTextbookExists((await review).textbookId);
|
||||
|
||||
return review
|
||||
return Review.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(review: Review): Promise<Review> {
|
||||
@ -32,7 +28,7 @@ export class ReviewService {
|
||||
return Review.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(review: Review, insertIfNotFound: boolean): Promise<Review | [affectedCount: number]> {
|
||||
async upsert(review: any, insertIfNotFound: boolean): Promise<Review | [affectedCount: number]> {
|
||||
if (review.id) {
|
||||
const existingReview = await this.findByPk(review.id);
|
||||
if (existingReview) {
|
||||
@ -40,8 +36,6 @@ export class ReviewService {
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
//const textbookExists = await this.checkTextbookExists(review.textbookId);
|
||||
|
||||
return Review.create(review as any)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { SeatService } from './seat.service';
|
||||
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';
|
||||
import { SeatDTO, SeatUpdateDTO } from './seat.dto';
|
||||
|
||||
@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 +32,12 @@ export class SeatController {
|
||||
}
|
||||
})
|
||||
async getAllSeats(@Res() res: Response) {
|
||||
// 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,
|
||||
@ -160,7 +167,7 @@ export class SeatController {
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new seat' })
|
||||
@ApiBody({ type: Seat, description: 'Seat data to insert' })
|
||||
@ApiBody({ type: SeatDTO, description: 'Seat data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid seat data',
|
||||
@ -178,7 +185,8 @@ export class SeatController {
|
||||
status: 201,
|
||||
description: 'Successfully created a seat',
|
||||
})
|
||||
async insert(@Body() seat: Seat, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() seat: SeatDTO, @Res() res: Response) {
|
||||
if (!seat) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
@ -188,7 +196,6 @@ export class SeatController {
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
delete seat.id;
|
||||
const response = await this.seatService.upsert(seat, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
@ -196,7 +203,7 @@ export class SeatController {
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing seat' })
|
||||
@ApiBody({ type: Seat, description: 'Seat data to update' })
|
||||
@ApiBody({ type: SeatUpdateDTO, description: 'Seat data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid seat data or ID missing',
|
||||
@ -227,7 +234,8 @@ export class SeatController {
|
||||
status: 200,
|
||||
description: 'Successfully updated seat',
|
||||
})
|
||||
async update(@Body() seat: Seat, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() seat: SeatUpdateDTO, @Res() res: Response) {
|
||||
if (!seat || !seat.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
|
||||
84
src/seat/seat.dto.ts
Normal file
84
src/seat/seat.dto.ts
Normal 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;
|
||||
}
|
||||
@ -20,6 +20,10 @@ export default class Seat extends Model {
|
||||
@Column({ type: DataType.TEXT, field: 'column' })
|
||||
column: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'available' })
|
||||
available: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
@Column({ type: DataType.TEXT, field: 'status' })
|
||||
status: string;
|
||||
|
||||
@ -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],
|
||||
})
|
||||
|
||||
@ -13,11 +13,7 @@ export class SeatService {
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<Seat> {
|
||||
|
||||
const seat = Seat.findByPk(id,)
|
||||
// //const textbookExists = await this.checkTextbookExists((await seat).textbookId);
|
||||
|
||||
return seat
|
||||
return Seat.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(seat: Seat): Promise<Seat> {
|
||||
@ -32,7 +28,11 @@ export class SeatService {
|
||||
return Seat.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(seat: Seat, insertIfNotFound: boolean): Promise<Seat | [affectedCount: number]> {
|
||||
async bookSeat(eventId: number, seatNumber: string) {
|
||||
return Seat.update({ available: 'booked' }, { where: { eventId: eventId, seatNumber: seatNumber } });
|
||||
}
|
||||
|
||||
async upsert(seat: any, insertIfNotFound: boolean): Promise<Seat | [affectedCount: number]> {
|
||||
if (seat.id) {
|
||||
const existingSeat = await this.findByPk(seat.id);
|
||||
if (existingSeat) {
|
||||
@ -40,8 +40,6 @@ export class SeatService {
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
//const textbookExists = await this.checkTextbookExists(seat.textbookId);
|
||||
|
||||
return Seat.create(seat as any)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { TheatreService } from './theatre.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../common/GenericResponse.model';
|
||||
import Theatre from './theatre.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { TheatreDTO, TheatreUpdateDTO } from './theatre.dto';
|
||||
|
||||
@ApiTags('theatre')
|
||||
@Controller('theatre')
|
||||
@ -160,7 +161,7 @@ export class TheatreController {
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new theatre' })
|
||||
@ApiBody({ type: Theatre, description: 'Theatre data to insert' })
|
||||
@ApiBody({ type: TheatreDTO, description: 'Theatre data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid theatre data',
|
||||
@ -178,7 +179,8 @@ export class TheatreController {
|
||||
status: 201,
|
||||
description: 'Successfully created a theatre',
|
||||
})
|
||||
async insert(@Body() theatre: Theatre, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() theatre: TheatreDTO, @Res() res: Response) {
|
||||
if (!theatre) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
@ -188,7 +190,6 @@ export class TheatreController {
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
delete theatre.id;
|
||||
const response = await this.theatreService.upsert(theatre, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
@ -196,7 +197,7 @@ export class TheatreController {
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing theatre' })
|
||||
@ApiBody({ type: Theatre, description: 'Theatre data to update' })
|
||||
@ApiBody({ type: TheatreUpdateDTO, description: 'Theatre data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid theatre data or ID missing',
|
||||
@ -227,7 +228,8 @@ export class TheatreController {
|
||||
status: 200,
|
||||
description: 'Successfully updated theatre',
|
||||
})
|
||||
async update(@Body() theatre: Theatre, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() theatre: TheatreUpdateDTO, @Res() res: Response) {
|
||||
if (!theatre || !theatre.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
|
||||
94
src/theatre/theatre.dto.ts
Normal file
94
src/theatre/theatre.dto.ts
Normal 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
|
||||
}
|
||||
@ -13,11 +13,7 @@ export class TheatreService {
|
||||
}
|
||||
|
||||
async findByPk(id: number): Promise<Theatre> {
|
||||
|
||||
const theatre = Theatre.findByPk(id,)
|
||||
// //const textbookExists = await this.checkTextbookExists((await theatre).textbookId);
|
||||
|
||||
return theatre
|
||||
return Theatre.findByPk(id);
|
||||
}
|
||||
|
||||
findOne(theatre: Theatre): Promise<Theatre> {
|
||||
@ -32,7 +28,7 @@ export class TheatreService {
|
||||
return Theatre.destroy({ where: { id: id } });
|
||||
}
|
||||
|
||||
async upsert(theatre: Theatre, insertIfNotFound: boolean): Promise<Theatre | [affectedCount: number]> {
|
||||
async upsert(theatre: any, insertIfNotFound: boolean): Promise<Theatre | [affectedCount: number]> {
|
||||
if (theatre.id) {
|
||||
const existingTheatre = await this.findByPk(theatre.id);
|
||||
if (existingTheatre) {
|
||||
@ -40,8 +36,6 @@ export class TheatreService {
|
||||
}
|
||||
}
|
||||
if (insertIfNotFound) {
|
||||
//const textbookExists = await this.checkTextbookExists(theatre.textbookId);
|
||||
|
||||
return Theatre.create(theatre as any)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UsePipes, ValidationPipe } from '@nestjs/common';
|
||||
import { TheatreAdditionalDetailsService } from './theatreAdditionalDetails.service';
|
||||
import { Response } from 'express';
|
||||
import { GenericResponse } from '../../common/GenericResponse.model';
|
||||
import TheatreAdditionalDetails from './theatreAdditionalDetails.entity';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { TheatreAdditionalDetailsDTO, TheatreAdditionalDetailsUpdateDTO } from './theatreAdditionalDetails.dto';
|
||||
|
||||
@ApiTags('theatreAdditionalDetails')
|
||||
@Controller('theatreAdditionalDetails')
|
||||
@ -160,7 +161,7 @@ export class TheatreAdditionalDetailsController {
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Insert a new theatreAdditionalDetails' })
|
||||
@ApiBody({ type: TheatreAdditionalDetails, description: 'TheatreAdditionalDetails data to insert' })
|
||||
@ApiBody({ type: TheatreAdditionalDetailsDTO, description: 'TheatreAdditionalDetails data to insert' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid theatreAdditionalDetails data',
|
||||
@ -178,7 +179,8 @@ export class TheatreAdditionalDetailsController {
|
||||
status: 201,
|
||||
description: 'Successfully created a theatreAdditionalDetails',
|
||||
})
|
||||
async insert(@Body() theatreAdditionalDetails: TheatreAdditionalDetails, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true}))
|
||||
async insert(@Body() theatreAdditionalDetails: TheatreAdditionalDetailsDTO, @Res() res: Response) {
|
||||
if (!theatreAdditionalDetails) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
@ -188,7 +190,6 @@ export class TheatreAdditionalDetailsController {
|
||||
}, null);
|
||||
return res.status(400).send(response);
|
||||
}
|
||||
delete theatreAdditionalDetails.id;
|
||||
const response = await this.theatreAdditionalDetailsService.upsert(theatreAdditionalDetails, true);
|
||||
const httpResponse = new GenericResponse(null, response);
|
||||
res.status(201).send(httpResponse);
|
||||
@ -196,7 +197,7 @@ export class TheatreAdditionalDetailsController {
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: 'Update an existing theatreAdditionalDetails' })
|
||||
@ApiBody({ type: TheatreAdditionalDetails, description: 'TheatreAdditionalDetails data to update' })
|
||||
@ApiBody({ type: TheatreAdditionalDetailsUpdateDTO, description: 'TheatreAdditionalDetails data to update' })
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'Invalid theatreAdditionalDetails data or ID missing',
|
||||
@ -227,7 +228,8 @@ export class TheatreAdditionalDetailsController {
|
||||
status: 200,
|
||||
description: 'Successfully updated theatreAdditionalDetails',
|
||||
})
|
||||
async update(@Body() theatreAdditionalDetails: TheatreAdditionalDetails, @Res() res: Response) {
|
||||
@UsePipes(new ValidationPipe({ whitelist: true, skipMissingProperties: true }))
|
||||
async update(@Body() theatreAdditionalDetails: TheatreAdditionalDetailsUpdateDTO, @Res() res: Response) {
|
||||
if (!theatreAdditionalDetails || !theatreAdditionalDetails.id) {
|
||||
const response = new GenericResponse({
|
||||
exception: true,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user