import { Body, Delete, Get, Path, Post, Put, Request, Response, Route, Security, SuccessResponse, Tags } from 'tsoa'; import { ValidationError } from '../middleware/errorHandler'; import { ChaptersLessonService } from '../services/ChaptersLesson.service'; import { CreateChapterResponse, UpdateChapterResponse, DeleteChapterResponse, ReorderChapterResponse, GetLessonResponse, CreateLessonResponse, UpdateLessonResponse, DeleteLessonResponse, ReorderLessonsResponse, AddQuestionResponse, UpdateQuestionResponse, DeleteQuestionResponse, CreateChapterBody, UpdateChapterBody, ReorderChapterBody, CreateLessonBody, UpdateLessonBody, ReorderLessonsBody, AddQuestionBody, UpdateQuestionBody, } from '../types/ChaptersLesson.typs'; const chaptersLessonService = new ChaptersLessonService(); @Route('api/instructors/courses/{courseId}') @Tags('ChaptersLessons - Instructor') export class ChaptersLessonInstructorController { // ============================================ // Chapter Endpoints // Note: Use CoursesInstructorController.getMyCourse to get chapters with full details // ============================================ /** * สร้าง chapter ใหม่ * Create a new chapter */ @Post('chapters') @Security('jwt', ['instructor']) @SuccessResponse('201', 'Chapter created successfully') @Response('401', 'Unauthorized') @Response('403', 'Forbidden') public async createChapter( @Request() request: any, @Path() courseId: number, @Body() body: CreateChapterBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.createChapter({ token, course_id: courseId, title: body.title, description: body.description, sort_order: body.sort_order, }); } /** * อัปเดต chapter * Update a chapter */ @Put('chapters/{chapterId}') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Chapter updated successfully') @Response('401', 'Unauthorized') @Response('403', 'Forbidden') @Response('404', 'Chapter not found') public async updateChapter( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Body() body: UpdateChapterBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.updateChapter({ token, course_id: courseId, chapter_id: chapterId, ...body, }); } /** * ลบ chapter * Delete a chapter */ @Delete('chapters/{chapterId}') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Chapter deleted successfully') @Response('401', 'Unauthorized') @Response('403', 'Forbidden') @Response('404', 'Chapter not found') public async deleteChapter( @Request() request: any, @Path() courseId: number, @Path() chapterId: number ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.deleteChapter({ token, course_id: courseId, chapter_id: chapterId }); } /** * เรียงลำดับ chapter ใหม่ * Reorder chapter */ @Put('chapters/{chapterId}/reorder') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Chapter reordered successfully') public async reorderChapter( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Body() body: ReorderChapterBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.reorderChapter({ token, course_id: courseId, chapter_id: chapterId, sort_order: body.sort_order, }); } // ============================================ // Lesson Endpoints // ============================================ /** * ดึงข้อมูล lesson พร้อม attachments และ quiz * Get lesson with attachments and quiz */ @Get('chapters/{chapterId}/lessons/{lessonId}') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Lesson retrieved successfully') public async getLesson( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Path() lessonId: number ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.getLesson({ token, course_id: courseId, chapter_id: chapterId, lesson_id: lessonId }); } /** * สร้าง lesson ใหม่ (สำหรับ QUIZ จะสร้าง quiz shell อัตโนมัติ) * Create a new lesson (for QUIZ type, quiz shell is created automatically) */ @Post('chapters/{chapterId}/lessons') @Security('jwt', ['instructor']) @SuccessResponse('201', 'Lesson created successfully') public async createLesson( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Body() body: CreateLessonBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.createLesson({ token, course_id: courseId, chapter_id: chapterId, title: body.title, content: body.content, type: body.type, sort_order: body.sort_order, }); } /** * อัปเดต lesson * Update a lesson */ @Put('chapters/{chapterId}/lessons/{lessonId}') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Lesson updated successfully') public async updateLesson( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Path() lessonId: number, @Body() body: UpdateLessonBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.updateLesson({ token, course_id: courseId, chapter_id: chapterId, lesson_id: lessonId, data: body, }); } // ============================================ // Video Upload Endpoints (multipart/form-data) // Note: These endpoints should be registered with express router // using multer middleware for actual file upload handling. // See: src/routes/lessons.routes.ts (to be created) // ============================================ /** * ลบ lesson * Delete a lesson (cannot delete if published) */ @Delete('chapters/{chapterId}/lessons/{lessonId}') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Lesson deleted successfully') public async deleteLesson( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Path() lessonId: number ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.deleteLesson({ token, course_id: courseId, chapter_id: chapterId, lesson_id: lessonId }); } /** * เรียงลำดับ lessons ใน chapter * Reorder lessons within a chapter */ @Put('chapters/{chapterId}/lessons/reorder') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Lessons reordered successfully') public async reorderLessons( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Body() body: ReorderLessonsBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.reorderLessons({ token, course_id: courseId, chapter_id: chapterId, lesson_id: body.lesson_id, sort_order: body.sort_order, }); } // ============================================ // Quiz Question Endpoints // ============================================ /** * เพิ่มคำถามให้ quiz lesson * Add a question to a quiz lesson */ @Post('chapters/{chapterId}/lessons/{lessonId}/questions') @Security('jwt', ['instructor']) @SuccessResponse('201', 'Question added successfully') public async addQuestion( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Path() lessonId: number, @Body() body: AddQuestionBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.addQuestion({ token, course_id: courseId, lesson_id: lessonId, ...body, }); } /** * อัปเดตคำถาม * Update a question */ @Put('chapters/{chapterId}/lessons/{lessonId}/questions/{questionId}') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Question updated successfully') public async updateQuestion( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Path() lessonId: number, @Path() questionId: number, @Body() body: UpdateQuestionBody ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.updateQuestion({ token, course_id: courseId, lesson_id: lessonId, question_id: questionId, ...body, }); } /** * ลบคำถาม * Delete a question */ @Delete('chapters/{chapterId}/lessons/{lessonId}/questions/{questionId}') @Security('jwt', ['instructor']) @SuccessResponse('200', 'Question deleted successfully') public async deleteQuestion( @Request() request: any, @Path() courseId: number, @Path() chapterId: number, @Path() lessonId: number, @Path() questionId: number ): Promise { const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) throw new ValidationError('No token provided'); return await chaptersLessonService.deleteQuestion({ token, course_id: courseId, lesson_id: lessonId, question_id: questionId, }); } }