feat: Implement lesson access control logic including enrollment, prerequisite, and quiz completion checks.
This commit is contained in:
parent
6d59ec06bf
commit
0308995d8e
4 changed files with 760 additions and 1 deletions
|
|
@ -0,0 +1,205 @@
|
|||
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<EnrollCourseResponse> {
|
||||
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<ListEnrolledCoursesResponse> {
|
||||
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<GetCourseLearningResponse> {
|
||||
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<GetLessonContentResponse> {
|
||||
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<CheckLessonAccessResponse> {
|
||||
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<SaveVideoProgressResponse> {
|
||||
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<GetVideoProgressResponse> {
|
||||
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<CompleteLessonResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) {
|
||||
throw new ValidationError('No token provided');
|
||||
}
|
||||
return await this.service.completeLesson({ token, lesson_id: lessonId });
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue