2026-01-09 10:14:13 +00:00
|
|
|
import { Body, Post, Route, Tags, SuccessResponse, Response, Example, Controller } from 'tsoa';
|
2026-01-09 06:28:15 +00:00
|
|
|
import { AuthService } from '../services/auth.service';
|
|
|
|
|
import {
|
|
|
|
|
LoginRequest,
|
|
|
|
|
RegisterRequest,
|
|
|
|
|
RefreshTokenRequest,
|
|
|
|
|
LoginResponse,
|
|
|
|
|
RegisterResponse,
|
|
|
|
|
RefreshTokenResponse
|
|
|
|
|
} from '../types/auth.types';
|
|
|
|
|
import { loginSchema, registerSchema, refreshTokenSchema } from '../validators/auth.validator';
|
|
|
|
|
import { ValidationError } from '../middleware/errorHandler';
|
|
|
|
|
|
|
|
|
|
@Route('api/auth')
|
|
|
|
|
@Tags('Authentication')
|
|
|
|
|
export class AuthController {
|
|
|
|
|
private authService = new AuthService();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* User login
|
2026-01-09 10:14:13 +00:00
|
|
|
* @summary Login with email and password
|
2026-01-09 06:28:15 +00:00
|
|
|
* @param body Login credentials
|
|
|
|
|
* @returns JWT token and user information
|
|
|
|
|
*/
|
|
|
|
|
@Post('login')
|
|
|
|
|
@SuccessResponse('200', 'Login successful')
|
|
|
|
|
@Response('401', 'Invalid credentials')
|
|
|
|
|
@Example<LoginResponse>({
|
|
|
|
|
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
|
|
|
refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
|
|
|
user: {
|
|
|
|
|
id: 1,
|
|
|
|
|
username: 'admin',
|
|
|
|
|
email: 'admin@elearning.local',
|
|
|
|
|
role: {
|
|
|
|
|
code: 'ADMIN',
|
|
|
|
|
name: {
|
|
|
|
|
th: 'ผู้ดูแลระบบ',
|
|
|
|
|
en: 'Administrator'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
profile: {
|
|
|
|
|
prefix: {
|
|
|
|
|
th: 'นาย',
|
|
|
|
|
en: 'Mr.'
|
|
|
|
|
},
|
|
|
|
|
first_name: 'Admin',
|
|
|
|
|
last_name: 'User',
|
|
|
|
|
avatar_url: undefined
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
public async login(@Body() body: LoginRequest): Promise<LoginResponse> {
|
|
|
|
|
// Validate input
|
2026-01-09 10:14:13 +00:00
|
|
|
const { error, value } = loginSchema.validate(body);
|
|
|
|
|
|
2026-01-09 06:28:15 +00:00
|
|
|
if (error) {
|
|
|
|
|
throw new ValidationError(error.details[0].message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await this.authService.login(body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* User registration
|
|
|
|
|
* @summary Register a new student account
|
|
|
|
|
* @param body Registration data
|
|
|
|
|
* @returns Created user information
|
|
|
|
|
*/
|
|
|
|
|
@Post('register')
|
|
|
|
|
@SuccessResponse('201', 'Registration successful')
|
|
|
|
|
@Response('400', 'Validation error')
|
|
|
|
|
@Response('409', 'Username or email already exists')
|
|
|
|
|
@Example<RegisterResponse>({
|
|
|
|
|
user: {
|
|
|
|
|
id: 4,
|
|
|
|
|
username: 'newstudent',
|
|
|
|
|
email: 'student@example.com',
|
|
|
|
|
role: {
|
|
|
|
|
code: 'STUDENT',
|
|
|
|
|
name: {
|
|
|
|
|
th: 'นักเรียน',
|
|
|
|
|
en: 'Student'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
profile: {
|
|
|
|
|
prefix: {
|
|
|
|
|
th: 'นาย',
|
|
|
|
|
en: 'Mr.'
|
|
|
|
|
},
|
|
|
|
|
first_name: 'John',
|
|
|
|
|
last_name: 'Doe'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
message: 'Registration successful'
|
|
|
|
|
})
|
|
|
|
|
public async register(@Body() body: RegisterRequest): Promise<RegisterResponse> {
|
|
|
|
|
// Validate input
|
|
|
|
|
const { error } = registerSchema.validate(body);
|
|
|
|
|
if (error) {
|
|
|
|
|
throw new ValidationError(error.details[0].message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await this.authService.register(body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Refresh access token
|
|
|
|
|
* @summary Get a new access token using refresh token
|
|
|
|
|
* @param body Refresh token
|
|
|
|
|
* @returns New access token and refresh token
|
|
|
|
|
*/
|
|
|
|
|
@Post('refresh')
|
|
|
|
|
@SuccessResponse('200', 'Token refreshed')
|
|
|
|
|
@Response('401', 'Invalid or expired refresh token')
|
|
|
|
|
@Example<RefreshTokenResponse>({
|
|
|
|
|
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
|
|
|
refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
|
|
|
})
|
|
|
|
|
public async refreshToken(@Body() body: RefreshTokenRequest): Promise<RefreshTokenResponse> {
|
|
|
|
|
// Validate input
|
|
|
|
|
const { error } = refreshTokenSchema.validate(body);
|
|
|
|
|
if (error) {
|
|
|
|
|
throw new ValidationError(error.details[0].message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await this.authService.refreshToken(body.refreshToken);
|
|
|
|
|
}
|
|
|
|
|
}
|