Files
travelplanning/main.ts
T

127 lines
3.4 KiB
TypeScript

import { NestFactory } from '@nestjs/core';
import { Module, Controller, Get, Post, Body, Param, ParseIntPipe, NotFoundException, BadRequestException, UnauthorizedException } from '@nestjs/common';
import { PrismaService } from './prisma.service.js';
import 'dotenv/config';
import * as bcrypt from 'bcrypt';
@Controller()
class AppController {
@Get()
getHello(): string {
return 'Travel Planning API is running!';
}
}
@Controller('v1/auth')
class AuthController {
constructor(private prisma: PrismaService) {}
@Get('status')
async getStatus() {
const userCount = await this.prisma.user.count();
console.log(`[Status Check] Users found: ${userCount}`);
return { isInitialSetup: userCount === 0 };
}
@Post('login')
async login(@Body() body: any) {
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');
}
return {
access_token: 'simulated-jwt-token',
user: {
id: user.id,
email: user.email,
name: user.name,
isAdmin: user.isAdmin,
},
};
}
@Post('signup')
async signup(@Body() body: any) {
const { email, password, name } = body;
// 1. Kiểm tra email tồn tại
const existingUser = await this.prisma.user.findUnique({ where: { email } });
if (existingUser) throw new BadRequestException('Email đã được sử dụng');
// 2. Logic "First User is Admin"
const userCount = await this.prisma.user.count();
const shouldBeAdmin = userCount === 0;
// 3. Hash mật khẩu
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 }
});
}
}
@Controller('v1/tours')
class TourController {
constructor(private prisma: PrismaService) {}
@Get('explore')
async getPublicTours() {
// Lấy các tour có ít nhất 1 ảnh và thông tin vị trí từ chặng đầu tiên
return this.prisma.tour.findMany({
take: 20,
include: {
photos: { take: 1 },
legs: {
take: 1,
include: {
places: { take: 1 }
}
}
}
});
}
@Get(':id')
async getTourDetails(@Param('id', ParseIntPipe) id: number) {
const tour = await this.prisma.tour.findUnique({
where: { id },
include: {
members: true,
photos: true,
legs: {
orderBy: { sequenceNumber: 'asc' },
include: {
places: { orderBy: { sequenceInLeg: 'asc' } },
expenses: true,
},
},
},
});
if (!tour) throw new NotFoundException(`Không tìm thấy Tour với ID ${id}`);
return tour;
}
}
@Module({
controllers: [AppController, AuthController, TourController],
providers: [PrismaService],
exports: [PrismaService]
})
class AppModule {}
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors(); // Cho phép Frontend gọi API
app.setGlobalPrefix('api'); // Tất cả API sẽ bắt đầu bằng /api/...
const port = process.env.PORT || 3001;
await app.listen(port);
console.log(`🚀 Server is running on: http://localhost:${port}`);
}
bootstrap();