From 8edc3770ebcaa6317b4772ab500a6d5f0dd7f27b Mon Sep 17 00:00:00 2001 From: JakkrapartXD Date: Wed, 11 Feb 2026 17:01:17 +0700 Subject: [PATCH] feat: Allow instructors to set rejected courses to draft and explicitly set course status to rejected upon administrative rejection. --- .../CoursesInstructorController.ts | 17 +++++++++++++ .../services/AdminCourseApproval.service.ts | 8 +++---- .../src/services/CoursesInstructor.service.ts | 24 +++++++++++++++++++ Backend/src/types/CoursesInstructor.types.ts | 10 ++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/Backend/src/controllers/CoursesInstructorController.ts b/Backend/src/controllers/CoursesInstructorController.ts index 840d6375..5b698807 100644 --- a/Backend/src/controllers/CoursesInstructorController.ts +++ b/Backend/src/controllers/CoursesInstructorController.ts @@ -21,6 +21,7 @@ import { GetQuizAttemptDetailResponse, GetEnrolledStudentDetailResponse, GetCourseApprovalHistoryResponse, + setCourseDraftResponse, } from '../types/CoursesInstructor.types'; import { CreateCourseValidator } from "../validators/CoursesInstructor.validator"; @@ -189,6 +190,22 @@ export class CoursesInstructorController { return await CoursesInstructorService.sendCourseForReview({ token, course_id: courseId }); } + /** + * ตั้งค่าคอร์สเป็น DRAFT + * Set course to draft + * @param courseId - รหัสคอร์ส / Course ID + */ + @Post('set-draft/{courseId}') + @Security('jwt', ['instructor']) + @SuccessResponse('200', 'Course set to draft successfully') + @Response('401', 'Invalid or expired token') + @Response('404', 'Course not found') + public async setCourseDraft(@Request() request: any, @Path() courseId: number): Promise { + const token = request.headers.authorization?.replace('Bearer ', ''); + if (!token) throw new ValidationError('No token provided') + return await CoursesInstructorService.setCourseDraft({ token, course_id: courseId }); + } + /** * ดึงประวัติการส่งอนุมัติคอร์สทั้งหมด * Get all course approval history diff --git a/Backend/src/services/AdminCourseApproval.service.ts b/Backend/src/services/AdminCourseApproval.service.ts index 4a83495b..5e9da6ea 100644 --- a/Backend/src/services/AdminCourseApproval.service.ts +++ b/Backend/src/services/AdminCourseApproval.service.ts @@ -300,11 +300,11 @@ export class AdminCourseApprovalService { } await prisma.$transaction([ - // Update course status back to DRAFT + // Update course status back to REJECTED prisma.course.update({ where: { id: courseId }, data: { - status: 'DRAFT', + status: 'REJECTED', rejection_reason: comment, approved_by: null, approved_at: null @@ -318,7 +318,7 @@ export class AdminCourseApprovalService { reviewed_by: decoded.id, action: 'REJECTED', previous_status: course.status, - new_status: 'DRAFT', + new_status: 'REJECTED', comment: comment } }) @@ -331,7 +331,7 @@ export class AdminCourseApprovalService { entityType: 'Course', entityId: courseId, oldValue: { status: 'PENDING' }, - newValue: { status: 'DRAFT' }, + newValue: { status: 'REJECTED' }, metadata: { comment: comment } }); diff --git a/Backend/src/services/CoursesInstructor.service.ts b/Backend/src/services/CoursesInstructor.service.ts index ab528c90..244e26ac 100644 --- a/Backend/src/services/CoursesInstructor.service.ts +++ b/Backend/src/services/CoursesInstructor.service.ts @@ -33,6 +33,8 @@ import { GetEnrolledStudentDetailInput, GetEnrolledStudentDetailResponse, GetCourseApprovalHistoryResponse, + setCourseDraft, + setCourseDraftResponse, } from "../types/CoursesInstructor.types"; import { auditService } from './audit.service'; import { AuditAction } from '@prisma/client'; @@ -327,6 +329,28 @@ export class CoursesInstructorService { } } + static async setCourseDraft(setCourseDraft: setCourseDraft): Promise { + try { + await this.validateCourseInstructor(setCourseDraft.token, setCourseDraft.course_id); + await prisma.course.update({ + where: { + id: setCourseDraft.course_id, + status: 'REJECTED' + }, + data: { + status: 'DRAFT' + } + }); + return { + code: 200, + message: 'Set course to draft successfully', + }; + } catch (error) { + logger.error('Failed to set course to draft', { error }); + throw error; + } + } + static async getCourseApprovals(token: string, courseId: number): Promise<{ code: number; message: string; diff --git a/Backend/src/types/CoursesInstructor.types.ts b/Backend/src/types/CoursesInstructor.types.ts index 99ad5ded..a10dac44 100644 --- a/Backend/src/types/CoursesInstructor.types.ts +++ b/Backend/src/types/CoursesInstructor.types.ts @@ -171,6 +171,16 @@ export interface sendCourseForReview { course_id: number; } +export interface setCourseDraft { + token: string; + course_id: number; +} + +export interface setCourseDraftResponse { + code: number; + message: string; +} + export interface CourseApprovalData { id: number; course_id: number;