var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import 'reflect-metadata'; import { NestFactory } from '@nestjs/core'; import { Module, Controller, Get, Post, Body, Param, Patch, Delete, ParseUUIDPipe, NotFoundException, BadRequestException, UnauthorizedException, UseGuards } from '@nestjs/common'; import { PrismaService } from './prisma.service.js'; import 'dotenv/config'; import * as bcrypt from 'bcrypt'; import { AdminGuard } from './admin.guard.js'; import { JwtModule, JwtService } from '@nestjs/jwt'; import { JwtAuthGuard } from './jwt-auth.guard.js'; import { JwtStrategy } from './jwt.strategy.js'; let AppController = class AppController { getHello() { return 'Travel Planning API is running!'; } }; __decorate([ Get(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", String) ], AppController.prototype, "getHello", null); AppController = __decorate([ Controller() ], AppController); let AuthController = class AuthController { constructor(prisma, jwtService) { this.prisma = prisma; this.jwtService = jwtService; } async getStatus() { const userCount = await this.prisma.user.count(); console.log(`[Status Check] Users found: ${userCount}`); return { isInitialSetup: userCount === 0 }; } async login(body) { const { email, password } = body; const user = await this.prisma.user.findUnique({ where: { email } }); if (!user || !(await bcrypt.compare(password, user.passwordHash))) { throw new UnauthorizedException('Email hoặc mật khẩu không chính xác'); } if (user.isBlocked) { throw new UnauthorizedException('Tài khoản của bạn đã bị khóa. Vui lòng liên hệ quản trị viên.'); } const payload = { email: user.email, sub: user.id }; return { access_token: this.jwtService.sign(payload), user: { id: user.id, email: user.email, name: user.name, isAdmin: user.isAdmin, }, }; } async signup(body) { const { email, password, name } = body; const existingUser = await this.prisma.user.findUnique({ where: { email } }); if (existingUser) throw new BadRequestException('Email đã được sử dụng'); const userCount = await this.prisma.user.count(); const shouldBeAdmin = userCount === 0; const passwordHash = await bcrypt.hash(password, 10); return this.prisma.user.create({ data: { email, passwordHash, name, isAdmin: shouldBeAdmin }, select: { id: true, email: true, name: true, isAdmin: true } }); } }; __decorate([ Get('status'), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], AuthController.prototype, "getStatus", null); __decorate([ Post('login'), __param(0, Body()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], AuthController.prototype, "login", null); __decorate([ Post('signup'), __param(0, Body()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], AuthController.prototype, "signup", null); AuthController = __decorate([ Controller('v1/auth'), __metadata("design:paramtypes", [PrismaService, JwtService]) ], AuthController); let TourController = class TourController { constructor(prisma) { this.prisma = prisma; } async getPublicTours() { return this.prisma.tour.findMany({ take: 20, include: { photos: { take: 1 }, legs: { take: 1, include: { locations: { take: 1 } } } } }); } async getTourDetails(id) { const tour = await this.prisma.tour.findUnique({ where: { id }, include: { participants: true, photos: true, legs: { orderBy: { sequence: 'asc' }, include: { locations: { orderBy: { plannedStart: 'asc' } }, expenses: true, }, }, }, }); if (!tour) throw new NotFoundException(`Không tìm thấy Tour với ID ${id}`); return tour; } }; __decorate([ Get('explore'), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], TourController.prototype, "getPublicTours", null); __decorate([ Get(':id'), __param(0, Param('id', ParseUUIDPipe)), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], TourController.prototype, "getTourDetails", null); TourController = __decorate([ Controller('v1/tours'), __metadata("design:paramtypes", [PrismaService]) ], TourController); let UserController = class UserController { constructor(prisma) { this.prisma = prisma; } async getAllUsers() { return this.prisma.user.findMany({ select: { id: true, email: true, name: true, isAdmin: true, isBlocked: true, createdAt: true } }); } async updateUser(id, data) { if (data.password) { data.passwordHash = await bcrypt.hash(data.password, 10); delete data.password; } return this.prisma.user.update({ where: { id }, data, select: { id: true, email: true, name: true, isAdmin: true, isBlocked: true } }); } async deleteUser(id) { const user = await this.prisma.user.findUnique({ where: { id } }); if (user?.isAdmin) { const adminCount = await this.prisma.user.count({ where: { isAdmin: true } }); if (adminCount <= 1) throw new BadRequestException('Không thể xóa Quản trị viên cuối cùng'); } await this.prisma.user.delete({ where: { id } }); return { success: true }; } async toggleBlock(id) { const user = await this.prisma.user.findUnique({ where: { id } }); if (!user) throw new NotFoundException('Người dùng không tồn tại'); return this.prisma.user.update({ where: { id }, data: { isBlocked: !user.isBlocked } }); } }; __decorate([ Get(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], UserController.prototype, "getAllUsers", null); __decorate([ Patch(':id'), __param(0, Param('id', ParseUUIDPipe)), __param(1, Body()), __metadata("design:type", Function), __metadata("design:paramtypes", [String, Object]), __metadata("design:returntype", Promise) ], UserController.prototype, "updateUser", null); __decorate([ Delete(':id'), __param(0, Param('id', ParseUUIDPipe)), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], UserController.prototype, "deleteUser", null); __decorate([ Post('block/:id'), __param(0, Param('id', ParseUUIDPipe)), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], UserController.prototype, "toggleBlock", null); UserController = __decorate([ Controller('v1/users'), UseGuards(JwtAuthGuard, AdminGuard), __metadata("design:paramtypes", [PrismaService]) ], UserController); let AppModule = class AppModule { }; AppModule = __decorate([ Module({ imports: [ JwtModule.register({ secret: process.env.JWT_SECRET || 'super-secret', signOptions: { expiresIn: '1d' }, }), ], controllers: [AppController, AuthController, TourController, UserController], providers: [PrismaService, JwtStrategy], exports: [PrismaService] }) ], AppModule); async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors(); app.setGlobalPrefix('api'); const port = process.env.PORT || 3001; await app.listen(port); console.log(`🚀 Server is running on: http://localhost:${port}`); } bootstrap(); //# sourceMappingURL=main.js.map