elearning/Backend/src/controllers/AuthController.ts

194 lines
6.4 KiB
TypeScript
Raw Normal View History

2026-01-13 03:10:44 +00:00
import { Body, Post, Route, Tags, SuccessResponse, Response, Example, Controller, Security } from 'tsoa';
2026-01-09 06:28:15 +00:00
import { AuthService } from '../services/auth.service';
import {
LoginRequest,
RegisterRequest,
RefreshTokenRequest,
2026-01-13 03:10:44 +00:00
ResetRequest,
ResetPasswordRequest,
2026-01-09 06:28:15 +00:00
LoginResponse,
RegisterResponse,
2026-01-13 03:10:44 +00:00
RefreshTokenResponse,
ChangePassword
2026-01-09 06:28:15 +00:00
} from '../types/auth.types';
2026-01-13 03:10:44 +00:00
import { loginSchema, registerSchema, refreshTokenSchema, resetRequestSchema, resetPasswordSchema, changePasswordSchema } from '../validators/auth.validator';
2026-01-09 06:28:15 +00:00
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',
2026-01-13 17:55:00 +07:00
updated_at: new Date('2024-01-01T00:00:00Z'),
created_at: new Date('2024-01-01T00:00:00Z'),
2026-01-09 06:28:15 +00:00
role: {
code: 'ADMIN',
name: {
th: 'ผู้ดูแลระบบ',
en: 'Administrator'
}
},
profile: {
prefix: {
th: 'นาย',
en: 'Mr.'
},
first_name: 'Admin',
last_name: 'User',
2026-01-13 17:55:00 +07:00
phone: null,
avatar_url: null,
birth_date: null
2026-01-09 06:28:15 +00:00
}
}
})
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',
2026-01-13 17:55:00 +07:00
updated_at: new Date('2024-01-01T00:00:00Z'),
created_at: new Date('2024-01-01T00:00:00Z'),
2026-01-09 06:28:15 +00:00
role: {
code: 'STUDENT',
name: {
th: 'นักเรียน',
en: 'Student'
}
},
profile: {
prefix: {
th: 'นาย',
en: 'Mr.'
},
first_name: 'John',
2026-01-13 17:55:00 +07:00
last_name: 'Doe',
phone: null,
avatar_url: null,
birth_date: null
2026-01-09 06:28:15 +00:00
}
},
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);
}
2026-01-13 03:10:44 +00:00
2026-01-13 03:48:49 +00:00
/**
* Reset password request
* @summary Request a password reset
* @param body Email address
* @returns Success message
*/
2026-01-13 03:10:44 +00:00
@Post('reset-request')
@SuccessResponse('200', 'Reset request successful')
@Response('401', 'Invalid or expired refresh token')
public async resetRequest(@Body() body: ResetRequest): Promise<{ message: string }> {
const { error } = resetRequestSchema.validate(body);
if (error) {
throw new ValidationError(error.details[0].message);
}
return await this.authService.resetRequest(body.email);
}
2026-01-13 03:48:49 +00:00
/**
* Reset password
* @summary Reset password using reset token
* @param body Reset token and new password
* @returns Success message
*/
2026-01-13 03:10:44 +00:00
@Post('reset-password')
@SuccessResponse('200', 'Password reset successful')
@Response('401', 'Invalid or expired reset token')
public async resetPassword(@Body() body: ResetPasswordRequest): Promise<{ message: string }> {
const { error } = resetPasswordSchema.validate(body);
if (error) {
throw new ValidationError(error.details[0].message);
}
return await this.authService.resetPassword(body.id, body.token, body.password);
}
2026-01-13 03:48:49 +00:00
/**
* Change password
* @summary Change password using old password
* @param body User ID, old password and new password
* @returns Success message
*/
2026-01-13 03:10:44 +00:00
@Post('change-password')
@Security('jwt')
@SuccessResponse('200', 'Password changed successfully')
@Response('401', 'Invalid or expired reset token')
public async changePassword(@Body() body: ChangePassword): Promise<{ message: string }> {
const { error } = changePasswordSchema.validate(body);
if (error) {
throw new ValidationError(error.details[0].message);
}
return await this.authService.changePassword(body.id, body.oldPassword, body.newPassword);
}
2026-01-09 06:28:15 +00:00
}