elearning/Backend/src/controllers/ChaptersLessonInstructorController.ts

355 lines
12 KiB
TypeScript

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,
ReorderQuestionResponse,
ReorderQuestionBody,
} 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<CreateChapterResponse> {
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<UpdateChapterResponse> {
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<DeleteChapterResponse> {
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<ReorderChapterResponse> {
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<GetLessonResponse> {
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<CreateLessonResponse> {
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<UpdateLessonResponse> {
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<DeleteLessonResponse> {
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}/reorder-lessons')
@Security('jwt', ['instructor'])
@SuccessResponse('200', 'Lessons reordered successfully')
public async reorderLessons(
@Request() request: any,
@Path() courseId: number,
@Path() chapterId: number,
@Body() body: ReorderLessonsBody
): Promise<ReorderLessonsResponse> {
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<AddQuestionResponse> {
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<UpdateQuestionResponse> {
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,
});
}
@Put('chapters/{chapterId}/lessons/{lessonId}/questions/{questionId}/reorder')
@Security('jwt', ['instructor'])
@SuccessResponse('200', 'Question reordered successfully')
public async reorderQuestion(
@Request() request: any,
@Path() courseId: number,
@Path() chapterId: number,
@Path() lessonId: number,
@Path() questionId: number,
@Body() body: ReorderQuestionBody
): Promise<ReorderQuestionResponse> {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) throw new ValidationError('No token provided');
return await chaptersLessonService.reorderQuestion({
token,
course_id: courseId,
lesson_id: lessonId,
question_id: questionId,
sort_order: body.sort_order,
});
}
/**
* ลบคำถาม
* 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<DeleteQuestionResponse> {
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,
});
}
}