260316:1255 Refactor to NestJS 11
Build and Deploy / deploy (push) Successful in 9m13s

This commit is contained in:
admin
2026-03-16 12:55:36 +07:00
parent c5c3ed9016
commit 25c50792e7
13 changed files with 1078 additions and 65 deletions
+3 -8
View File
@@ -27,12 +27,7 @@ import {
ApiResponse,
ApiBody,
} from '@nestjs/swagger';
import { Request } from 'express';
// สร้าง Interface สำหรับ Request ที่มี User
interface RequestWithUser extends Request {
user: any;
}
import type { RequestWithUser, RequestWithRefreshUser } from '../interfaces/request-with-user.interface';
@ApiTags('Authentication')
@Controller('auth')
@@ -95,7 +90,7 @@ export class AuthController {
},
},
})
async refresh(@Req() req: RequestWithUser) {
async refresh(@Req() req: RequestWithRefreshUser) {
return this.authService.refreshToken(req.user.sub, req.user.refreshToken);
}
@@ -121,7 +116,7 @@ export class AuthController {
}
// ส่ง refresh token ไปด้วยถ้ามี (ใน header หรือ body)
// สำหรับตอนนี้ส่งแค่ access token ไป blacklist
return this.authService.logout(req.user.sub, token);
return this.authService.logout(req.user.user_id, token);
}
@UseGuards(JwtAuthGuard)
@@ -17,6 +17,7 @@ import {
import { AuthService } from './auth.service';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { User } from '../../modules/user/entities/user.entity';
import type { RequestWithUser } from '../interfaces/request-with-user.interface';
@ApiTags('Authentication')
@Controller('auth/sessions')
@@ -28,7 +29,7 @@ export class SessionController {
@Get()
@ApiOperation({ summary: 'List all active sessions (Admin/DC Only)' })
@ApiResponse({ status: 200, description: 'List of active sessions' })
async getActiveSessions(@Req() req: any) {
async getActiveSessions(@Req() req: RequestWithUser) {
this.checkAdminRole(req.user);
return this.authService.getActiveSessions();
}
@@ -36,7 +37,10 @@ export class SessionController {
@Delete(':id')
@ApiOperation({ summary: 'Revoke a session by ID (Admin/DC Only)' })
@ApiResponse({ status: 200, description: 'Session revoked' })
async revokeSession(@Param('id', ParseIntPipe) id: number, @Req() req: any) {
async revokeSession(
@Param('id', ParseIntPipe) id: number,
@Req() req: RequestWithUser
) {
this.checkAdminRole(req.user);
await this.authService.revokeSession(id);
return { message: 'Session revoked successfully' };
@@ -7,11 +7,12 @@ import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Request } from 'express';
import type { JwtPayload } from './jwt.strategy';
@Injectable()
export class JwtRefreshStrategy extends PassportStrategy(
Strategy,
'jwt-refresh',
'jwt-refresh'
) {
constructor(configService: ConfigService) {
super({
@@ -23,7 +24,7 @@ export class JwtRefreshStrategy extends PassportStrategy(
});
}
async validate(req: Request, payload: any) {
async validate(req: Request, payload: JwtPayload) {
const refreshToken = ExtractJwt.fromAuthHeaderAsBearerToken()(req);
return {
...payload,
@@ -20,14 +20,7 @@ import type { Response } from 'express';
import { FileInterceptor } from '@nestjs/platform-express';
import { FileStorageService } from './file-storage.service';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
// Interface เพื่อระบุ Type ของ Request ที่ผ่าน JwtAuthGuard มาแล้ว
interface RequestWithUser {
user: {
userId: number;
username: string;
};
}
import type { RequestWithUser } from '../interfaces/request-with-user.interface';
@Controller('files')
@UseGuards(JwtAuthGuard)
@@ -53,7 +46,7 @@ export class FileStorageController {
@Request() req: RequestWithUser
) {
// ส่ง userId จาก Token ไปด้วย
return this.fileStorageService.upload(file, req.user.userId);
return this.fileStorageService.upload(file, req.user.user_id);
}
/**
@@ -90,7 +83,7 @@ export class FileStorageController {
@Request() req: RequestWithUser
) {
// ส่ง userId ไปด้วยเพื่อตรวจสอบความเป็นเจ้าของ
await this.fileStorageService.delete(id, req.user.userId);
await this.fileStorageService.delete(id, req.user.user_id);
return { message: 'File deleted successfully', id };
}
}
@@ -0,0 +1,30 @@
// File: src/common/interfaces/request-with-user.interface.ts
// NestJS 11: Shared typed Request interfaces (replaces scattered `req: any` patterns)
import { Request } from 'express';
import { User } from '../../modules/user/entities/user.entity';
/**
* Request object after JwtAuthGuard has validated the token.
* Passport attaches the User entity returned by JwtStrategy.validate() to `req.user`.
*/
export interface RequestWithUser extends Request {
user: User;
}
/**
* Payload shape returned by JwtRefreshStrategy.validate().
* Contains JWT claims + the raw refresh token for rotation.
*/
export interface JwtRefreshPayload {
sub: number;
username: string;
refreshToken: string;
}
/**
* Request object after JwtRefreshGuard has validated the refresh token.
*/
export interface RequestWithRefreshUser extends Request {
user: JwtRefreshPayload;
}