feat: Implement granular API for video upload/update and attachment management with dedicated types and endpoints.
This commit is contained in:
parent
e082c77946
commit
be7348c74d
4 changed files with 580 additions and 215 deletions
|
|
@ -24,6 +24,8 @@ import {
|
|||
UpdateQuestionBody,
|
||||
ReorderQuestionResponse,
|
||||
ReorderQuestionBody,
|
||||
UpdateQuizResponse,
|
||||
UpdateQuizBody,
|
||||
} from '../types/ChaptersLesson.typs';
|
||||
|
||||
const chaptersLessonService = new ChaptersLessonService();
|
||||
|
|
@ -352,4 +354,28 @@ export class ChaptersLessonInstructorController {
|
|||
question_id: questionId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* อัพเดตการตั้งค่า Quiz
|
||||
* Update quiz settings
|
||||
*/
|
||||
@Put('chapters/{chapterId}/lessons/{lessonId}/quiz')
|
||||
@Security('jwt', ['instructor'])
|
||||
@SuccessResponse('200', 'Quiz updated successfully')
|
||||
public async updateQuiz(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Path() chapterId: number,
|
||||
@Path() lessonId: number,
|
||||
@Body() body: UpdateQuizBody
|
||||
): Promise<UpdateQuizResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
return await chaptersLessonService.updateQuiz({
|
||||
token,
|
||||
course_id: courseId,
|
||||
lesson_id: lessonId,
|
||||
...body,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
import { Path, Post, Put, Request, Response, Route, Security, SuccessResponse, Tags, UploadedFile, UploadedFiles } from 'tsoa';
|
||||
import { Delete, Path, Post, Put, Request, Response, Route, Security, SuccessResponse, Tags, UploadedFile } from 'tsoa';
|
||||
import { ValidationError } from '../middleware/errorHandler';
|
||||
import { ChaptersLessonService } from '../services/ChaptersLesson.service';
|
||||
import { UploadedFileInfo, CreateLessonResponse, UpdateLessonResponse } from '../types/ChaptersLesson.typs';
|
||||
import {
|
||||
UploadedFileInfo,
|
||||
CreateLessonResponse,
|
||||
UpdateLessonResponse,
|
||||
VideoOperationResponse,
|
||||
AttachmentOperationResponse,
|
||||
DeleteAttachmentResponse
|
||||
} from '../types/ChaptersLesson.typs';
|
||||
|
||||
const chaptersLessonService = new ChaptersLessonService();
|
||||
|
||||
|
|
@ -10,30 +17,28 @@ const chaptersLessonService = new ChaptersLessonService();
|
|||
export class LessonsController {
|
||||
|
||||
/**
|
||||
* เพิ่มวิดีโอและไฟล์แนบให้บทเรียน VIDEO ที่มีอยู่แล้ว
|
||||
* Add video and attachments to an existing VIDEO type lesson
|
||||
* อัพโหลดวิดีโอใหม่ให้บทเรียน (ครั้งแรก)
|
||||
* Upload video to lesson (first time)
|
||||
*
|
||||
* @param courseId Course ID
|
||||
* @param chapterId Chapter ID
|
||||
* @param chapterId Chapter ID
|
||||
* @param lessonId Lesson ID
|
||||
* @param video ไฟล์วิดีโอ (required)
|
||||
* @param attachments ไฟล์แนบ
|
||||
*/
|
||||
@Post('{lessonId}/video')
|
||||
@Security('jwt', ['instructor'])
|
||||
@SuccessResponse('200', 'Video added successfully')
|
||||
@Response('400', 'Validation error')
|
||||
@SuccessResponse('200', 'Video uploaded successfully')
|
||||
@Response('400', 'Validation error - Video already exists')
|
||||
@Response('401', 'Unauthorized')
|
||||
@Response('403', 'Forbidden')
|
||||
@Response('404', 'Lesson not found')
|
||||
public async addVideoToLesson(
|
||||
public async uploadVideo(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Path() chapterId: number,
|
||||
@Path() lessonId: number,
|
||||
@UploadedFile() video: Express.Multer.File,
|
||||
@UploadedFiles() attachments?: Express.Multer.File[]
|
||||
): Promise<CreateLessonResponse> {
|
||||
@UploadedFile() video: Express.Multer.File
|
||||
): Promise<VideoOperationResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
|
||||
|
|
@ -41,7 +46,6 @@ export class LessonsController {
|
|||
throw new ValidationError('Video file is required');
|
||||
}
|
||||
|
||||
// Transform files to UploadedFileInfo
|
||||
const videoInfo: UploadedFileInfo = {
|
||||
originalname: video.originalname,
|
||||
mimetype: video.mimetype,
|
||||
|
|
@ -49,34 +53,22 @@ export class LessonsController {
|
|||
buffer: video.buffer,
|
||||
};
|
||||
|
||||
let attachmentsInfo: UploadedFileInfo[] | undefined;
|
||||
if (attachments && attachments.length > 0) {
|
||||
attachmentsInfo = attachments.map(file => ({
|
||||
originalname: file.originalname,
|
||||
mimetype: file.mimetype,
|
||||
size: file.size,
|
||||
buffer: file.buffer,
|
||||
}));
|
||||
}
|
||||
|
||||
return await chaptersLessonService.addVideoLesson({
|
||||
return await chaptersLessonService.uploadVideo({
|
||||
token,
|
||||
course_id: courseId,
|
||||
lesson_id: lessonId,
|
||||
video: videoInfo,
|
||||
attachments: attachmentsInfo,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* อัปเดตวิดีโอและไฟล์แนบของบทเรียน VIDEO
|
||||
* Update video and attachments of an existing VIDEO type lesson
|
||||
* อัพเดต (เปลี่ยน) วิดีโอของบทเรียน
|
||||
* Update (replace) video in lesson
|
||||
*
|
||||
* @param courseId Course ID
|
||||
* @param chapterId Chapter ID
|
||||
* @param lessonId Lesson ID
|
||||
* @param video ไฟล์วิดีโอใหม่
|
||||
* @param attachments ไฟล์แนบใหม่
|
||||
* @param video ไฟล์วิดีโอใหม่ (required)
|
||||
*/
|
||||
@Put('{lessonId}/video')
|
||||
@Security('jwt', ['instructor'])
|
||||
|
|
@ -85,45 +77,111 @@ export class LessonsController {
|
|||
@Response('401', 'Unauthorized')
|
||||
@Response('403', 'Forbidden')
|
||||
@Response('404', 'Lesson not found')
|
||||
public async updateVideoLesson(
|
||||
public async updateVideo(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Path() chapterId: number,
|
||||
@Path() lessonId: number,
|
||||
@UploadedFile() video?: Express.Multer.File,
|
||||
@UploadedFiles() attachments?: Express.Multer.File[]
|
||||
): Promise<UpdateLessonResponse> {
|
||||
@UploadedFile() video: Express.Multer.File
|
||||
): Promise<VideoOperationResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
|
||||
// Transform files to UploadedFileInfo
|
||||
let videoInfo: UploadedFileInfo | undefined;
|
||||
let attachmentsInfo: UploadedFileInfo[] | undefined;
|
||||
|
||||
if (video) {
|
||||
videoInfo = {
|
||||
originalname: video.originalname,
|
||||
mimetype: video.mimetype,
|
||||
size: video.size,
|
||||
buffer: video.buffer,
|
||||
};
|
||||
if (!video) {
|
||||
throw new ValidationError('Video file is required');
|
||||
}
|
||||
|
||||
if (attachments && attachments.length > 0) {
|
||||
attachmentsInfo = attachments.map(file => ({
|
||||
originalname: file.originalname,
|
||||
mimetype: file.mimetype,
|
||||
size: file.size,
|
||||
buffer: file.buffer,
|
||||
}));
|
||||
}
|
||||
const videoInfo: UploadedFileInfo = {
|
||||
originalname: video.originalname,
|
||||
mimetype: video.mimetype,
|
||||
size: video.size,
|
||||
buffer: video.buffer,
|
||||
};
|
||||
|
||||
return await chaptersLessonService.updateVideoLesson({
|
||||
return await chaptersLessonService.updateVideo({
|
||||
token,
|
||||
course_id: courseId,
|
||||
lesson_id: lessonId,
|
||||
video: videoInfo,
|
||||
attachments: attachmentsInfo,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* อัพโหลดไฟล์แนบทีละไฟล์
|
||||
* Upload a single attachment to lesson
|
||||
*
|
||||
* @param courseId Course ID
|
||||
* @param chapterId Chapter ID
|
||||
* @param lessonId Lesson ID
|
||||
* @param attachment ไฟล์แนบ (required)
|
||||
*/
|
||||
@Post('{lessonId}/attachments')
|
||||
@Security('jwt', ['instructor'])
|
||||
@SuccessResponse('200', 'Attachment uploaded successfully')
|
||||
@Response('400', 'Validation error')
|
||||
@Response('401', 'Unauthorized')
|
||||
@Response('403', 'Forbidden')
|
||||
@Response('404', 'Lesson not found')
|
||||
public async uploadAttachment(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Path() chapterId: number,
|
||||
@Path() lessonId: number,
|
||||
@UploadedFile() attachment: Express.Multer.File
|
||||
): Promise<AttachmentOperationResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
|
||||
if (!attachment) {
|
||||
throw new ValidationError('Attachment file is required');
|
||||
}
|
||||
|
||||
const attachmentInfo: UploadedFileInfo = {
|
||||
originalname: attachment.originalname,
|
||||
mimetype: attachment.mimetype,
|
||||
size: attachment.size,
|
||||
buffer: attachment.buffer,
|
||||
};
|
||||
|
||||
return await chaptersLessonService.uploadAttachment({
|
||||
token,
|
||||
course_id: courseId,
|
||||
lesson_id: lessonId,
|
||||
attachment: attachmentInfo,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ลบไฟล์แนบทีละไฟล์
|
||||
* Delete a single attachment from lesson
|
||||
*
|
||||
* @param courseId Course ID
|
||||
* @param chapterId Chapter ID
|
||||
* @param lessonId Lesson ID
|
||||
* @param attachmentId Attachment ID
|
||||
*/
|
||||
@Delete('{lessonId}/attachments/{attachmentId}')
|
||||
@Security('jwt', ['instructor'])
|
||||
@SuccessResponse('200', 'Attachment deleted successfully')
|
||||
@Response('400', 'Validation error')
|
||||
@Response('401', 'Unauthorized')
|
||||
@Response('403', 'Forbidden')
|
||||
@Response('404', 'Attachment not found')
|
||||
public async deleteAttachment(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Path() chapterId: number,
|
||||
@Path() lessonId: number,
|
||||
@Path() attachmentId: number
|
||||
): Promise<DeleteAttachmentResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
|
||||
return await chaptersLessonService.deleteAttachment({
|
||||
token,
|
||||
course_id: courseId,
|
||||
lesson_id: lessonId,
|
||||
attachment_id: attachmentId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue