diff --git a/Backend/src/controllers/CoursesInstructorController.ts b/Backend/src/controllers/CoursesInstructorController.ts index a401c852..840d6375 100644 --- a/Backend/src/controllers/CoursesInstructorController.ts +++ b/Backend/src/controllers/CoursesInstructorController.ts @@ -20,6 +20,7 @@ import { GetQuizScoresResponse, GetQuizAttemptDetailResponse, GetEnrolledStudentDetailResponse, + GetCourseApprovalHistoryResponse, } from '../types/CoursesInstructor.types'; import { CreateCourseValidator } from "../validators/CoursesInstructor.validator"; @@ -398,4 +399,24 @@ export class CoursesInstructorController { student_id: studentId, }); } + + /** + * ดึงประวัติการขออนุมัติคอร์ส + * Get course approval history for instructor to see rejection reasons + * @param courseId - รหัสคอร์ส / Course ID + */ + @Get('{courseId}/approval-history') + @Security('jwt', ['instructor']) + @SuccessResponse('200', 'Approval history retrieved successfully') + @Response('401', 'Invalid or expired token') + @Response('403', 'Not an instructor of this course') + @Response('404', 'Course not found') + public async getCourseApprovalHistory( + @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.getCourseApprovalHistory(token, courseId); + } } \ No newline at end of file diff --git a/Backend/src/services/CoursesInstructor.service.ts b/Backend/src/services/CoursesInstructor.service.ts index 0acd8d0e..ab528c90 100644 --- a/Backend/src/services/CoursesInstructor.service.ts +++ b/Backend/src/services/CoursesInstructor.service.ts @@ -32,6 +32,7 @@ import { GetQuizAttemptDetailResponse, GetEnrolledStudentDetailInput, GetEnrolledStudentDetailResponse, + GetCourseApprovalHistoryResponse, } from "../types/CoursesInstructor.types"; import { auditService } from './audit.service'; import { AuditAction } from '@prisma/client'; @@ -1103,4 +1104,60 @@ export class CoursesInstructorService { throw error; } } + + /** + * ดึงประวัติการขออนุมัติคอร์ส + * Get course approval history for instructor to see rejection reasons + */ + static async getCourseApprovalHistory(token: string, courseId: number): Promise { + try { + const decoded = jwt.verify(token, config.jwt.secret) as { id: number }; + + // Validate instructor access + await this.validateCourseInstructor(token, courseId); + + // Get course with approval history + const course = await prisma.course.findUnique({ + where: { id: courseId }, + include: { + courseApprovals: { + orderBy: { created_at: 'desc' }, + include: { + submitter: { + select: { id: true, username: true, email: true } + }, + reviewer: { + select: { id: true, username: true, email: true } + } + } + } + } + }); + + if (!course) { + throw new NotFoundError('Course not found'); + } + + return { + code: 200, + message: 'Course approval history retrieved successfully', + data: { + course_id: course.id, + course_title: course.title as { th: string; en: string }, + current_status: course.status, + approval_history: course.courseApprovals.map(a => ({ + id: a.id, + action: a.action, + comment: a.comment, + created_at: a.created_at, + submitter: a.submitter, + reviewer: a.reviewer + })) + } + }; + } catch (error) { + logger.error(`Error getting course approval history: ${error}`); + throw error; + } + } } diff --git a/Backend/src/types/CoursesInstructor.types.ts b/Backend/src/types/CoursesInstructor.types.ts index eb977fc0..99ad5ded 100644 --- a/Backend/src/types/CoursesInstructor.types.ts +++ b/Backend/src/types/CoursesInstructor.types.ts @@ -390,3 +390,31 @@ export interface GetEnrolledStudentDetailResponse { data: EnrolledStudentDetailData; } +// Course Approval History Types +export interface ApprovalHistoryItem { + id: number; + action: string; + comment: string | null; + created_at: Date; + submitter: { + id: number; + username: string; + email: string; + } | null; + reviewer: { + id: number; + username: string; + email: string; + } | null; +} + +export interface GetCourseApprovalHistoryResponse { + code: number; + message: string; + data: { + course_id: number; + course_title: { th: string; en: string }; + current_status: string; + approval_history: ApprovalHistoryItem[]; + }; +}