import { Get, Body, Post, Route, Tags, SuccessResponse, Response, Security, Path, Request, Query } from 'tsoa'; import { ValidationError } from '../middleware/errorHandler'; import { CoursesStudentService } from '../services/CoursesStudent.service'; import { EnrollCourseResponse, ListEnrolledCoursesResponse, GetCourseLearningResponse, GetLessonContentResponse, CheckLessonAccessResponse, SaveVideoProgressResponse, SaveVideoProgressBody, GetVideoProgressResponse, CompleteLessonResponse, } from '../types/CoursesStudent.types'; import { EnrollmentStatus } from '@prisma/client'; @Route('api/students') @Tags('CoursesStudent') export class CoursesStudentController { private service = new CoursesStudentService(); /** * ลงทะเบียนเรียนในคอร์ส * Enroll in a course * @param courseId - รหัสคอร์ส / Course ID */ @Post('courses/{courseId}/enroll') @Security('jwt', ['student']) @SuccessResponse('200', 'Enrolled successfully') @Response('401', 'Invalid or expired token') @Response('404', 'Course not found') @Response('409', 'Already enrolled in this course') public async enrollCourse(@Request() request: any, @Path() courseId: number): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new ValidationError('No token provided'); } return await this.service.enrollCourse({ token, course_id: courseId }); } /** * ดึงรายการคอร์สที่ลงทะเบียนเรียน * Get list of enrolled courses * @param page - หน้าที่ต้องการดึง / Page number * @param limit - จำนวนรายการต่อหน้า / Items per page * @param status - สถานะการลงทะเบียน / Enrollment status */ @Get('courses') @Security('jwt', ['student']) @SuccessResponse('200', 'Enrolled courses retrieved successfully') @Response('401', 'Invalid or expired token') public async getEnrolledCourses( @Request() request: any, @Query() page?: number, @Query() limit?: number, @Query() status?: EnrollmentStatus ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new ValidationError('No token provided'); } return await this.service.GetEnrolledCourses({ token, page, limit, status }); } /** * ดึงข้อมูลหน้าเรียนคอร์ส (พร้อมสถานะการล็อคบทเรียน) * Get course learning page with lesson lock status * @param courseId - รหัสคอร์ส / Course ID */ @Get('courses/{courseId}/learn') @Security('jwt', ['student']) @SuccessResponse('200', 'Course learning data retrieved successfully') @Response('401', 'Invalid or expired token') @Response('403', 'Not enrolled in this course') @Response('404', 'Course not found') public async getCourseLearning(@Request() request: any, @Path() courseId: number): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new ValidationError('No token provided'); } return await this.service.getCourseLearning({ token, course_id: courseId }); } /** * ดึงเนื้อหาบทเรียน (ตรวจสอบเงื่อนไขก่อนหน้า) * Get lesson content (checks prerequisites) * @param courseId - รหัสคอร์ส / Course ID * @param lessonId - รหัสบทเรียน / Lesson ID */ @Get('courses/{courseId}/lessons/{lessonId}') @Security('jwt', ['student']) @SuccessResponse('200', 'Lesson content retrieved successfully') @Response('401', 'Invalid or expired token') @Response('403', 'Not enrolled in this course or lesson is locked') @Response('404', 'Lesson not found') public async getLessonContent( @Request() request: any, @Path() courseId: number, @Path() lessonId: number ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new ValidationError('No token provided'); } return await this.service.getlessonContent({ token, course_id: courseId, lesson_id: lessonId }); } /** * ตรวจสอบสิทธิ์เข้าถึงบทเรียน (ไม่โหลดเนื้อหา) * Check lesson access without loading content * @param courseId - รหัสคอร์ส / Course ID * @param lessonId - รหัสบทเรียน / Lesson ID */ @Get('courses/{courseId}/lessons/{lessonId}/access-check') @Security('jwt', ['student']) @SuccessResponse('200', 'Access check completed') @Response('401', 'Invalid or expired token') @Response('404', 'Lesson not found') public async checkLessonAccess( @Request() request: any, @Path() courseId: number, @Path() lessonId: number ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new ValidationError('No token provided'); } return await this.service.checkAccessLesson({ token, course_id: courseId, lesson_id: lessonId }); } /** * บันทึกความคืบหน้าการดูวิดีโอ * Save video progress * @param lessonId - รหัสบทเรียน / Lesson ID */ @Post('lessons/{lessonId}/progress') @Security('jwt', ['student']) @SuccessResponse('200', 'Video progress saved successfully') @Response('401', 'Invalid or expired token') @Response('403', 'Not enrolled in this course') @Response('404', 'Lesson not found') public async saveVideoProgress( @Request() request: any, @Path() lessonId: number, @Body() body: SaveVideoProgressBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new ValidationError('No token provided'); } return await this.service.saveVideoProgress({ token, lesson_id: lessonId, video_progress_seconds: body.video_progress_seconds, video_duration_seconds: body.video_duration_seconds, }); } /** * ดึงความคืบหน้าการดูวิดีโอ * Get video progress * @param lessonId - รหัสบทเรียน / Lesson ID */ @Get('lessons/{lessonId}/progress') @Security('jwt', ['student']) @SuccessResponse('200', 'Video progress retrieved successfully') @Response('401', 'Invalid or expired token') @Response('403', 'Not enrolled in this course') @Response('404', 'Lesson not found') public async getVideoProgress( @Request() request: any, @Path() lessonId: number ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new ValidationError('No token provided'); } return await this.service.getVideoProgress({ token, lesson_id: lessonId }); } /** * ทำเครื่องหมายบทเรียนว่าเรียนจบ * Mark lesson as complete * @param courseId - รหัสคอร์ส / Course ID * @param lessonId - รหัสบทเรียน / Lesson ID */ @Post('courses/{courseId}/lessons/{lessonId}/complete') @Security('jwt', ['student']) @SuccessResponse('200', 'Lesson marked as complete') @Response('401', 'Invalid or expired token') @Response('403', 'Not enrolled in this course') @Response('404', 'Lesson not found') public async completeLesson( @Request() request: any, @Path() courseId: number, @Path() lessonId: number ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new ValidationError('No token provided'); } return await this.service.completeLesson({ token, lesson_id: lessonId }); } }