feat: add instructor endpoints for student progress tracking and quiz score management
Add four new instructor endpoints: getEnrolledStudents to view all enrolled students with progress, getQuizScores to view quiz scores for all students in a lesson, getQuizAttemptDetail to view detailed quiz attempt for a specific student, and searchStudents to search enrolled students by name/email/username. Add getQuizAttempts endpoint for students to retrieve their own quiz attempt history. All endpoints include
This commit is contained in:
parent
a648c41b72
commit
80d7372dfa
6 changed files with 832 additions and 1 deletions
|
|
@ -15,7 +15,11 @@ import {
|
|||
submitCourseResponse,
|
||||
listinstructorCourseResponse,
|
||||
GetCourseApprovalsResponse,
|
||||
SearchInstructorResponse
|
||||
SearchInstructorResponse,
|
||||
GetEnrolledStudentsResponse,
|
||||
GetQuizScoresResponse,
|
||||
GetQuizAttemptDetailResponse,
|
||||
SearchStudentsResponse,
|
||||
} from '../types/CoursesInstructor.types';
|
||||
import { CreateCourseValidator } from "../validators/CoursesInstructor.validator";
|
||||
|
||||
|
|
@ -262,4 +266,121 @@ export class CoursesInstructorController {
|
|||
if (!token) throw new ValidationError('No token provided')
|
||||
return await CoursesInstructorService.setPrimaryInstructor({ token, course_id: courseId, user_id: userId });
|
||||
}
|
||||
|
||||
/**
|
||||
* ดึงรายชื่อนักเรียนที่ลงทะเบียนในคอร์สพร้อม progress
|
||||
* Get all enrolled students with their progress
|
||||
* @param courseId - รหัสคอร์ส / Course ID
|
||||
* @param page - หน้าที่ต้องการ / Page number
|
||||
* @param limit - จำนวนต่อหน้า / Items per page
|
||||
*/
|
||||
@Get('{courseId}/students')
|
||||
@Security('jwt', ['instructor'])
|
||||
@SuccessResponse('200', 'Enrolled students retrieved successfully')
|
||||
@Response('401', 'Invalid or expired token')
|
||||
@Response('403', 'Not an instructor of this course')
|
||||
public async getEnrolledStudents(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Query() page?: number,
|
||||
@Query() limit?: number
|
||||
): Promise<GetEnrolledStudentsResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
return await CoursesInstructorService.getEnrolledStudents({
|
||||
token,
|
||||
course_id: courseId,
|
||||
page,
|
||||
limit,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ดึงคะแนนสอบของนักเรียนทุกคนในแต่ละ lesson quiz
|
||||
* Get quiz scores of all students for a specific lesson
|
||||
* @param courseId - รหัสคอร์ส / Course ID
|
||||
* @param lessonId - รหัสบทเรียน / Lesson ID
|
||||
* @param page - หน้าที่ต้องการ / Page number
|
||||
* @param limit - จำนวนต่อหน้า / Items per page
|
||||
*/
|
||||
@Get('{courseId}/lessons/{lessonId}/quiz/scores')
|
||||
@Security('jwt', ['instructor'])
|
||||
@SuccessResponse('200', 'Quiz scores retrieved successfully')
|
||||
@Response('401', 'Invalid or expired token')
|
||||
@Response('403', 'Not an instructor of this course')
|
||||
@Response('404', 'Lesson or quiz not found')
|
||||
public async getQuizScores(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Path() lessonId: number,
|
||||
@Query() page?: number,
|
||||
@Query() limit?: number
|
||||
): Promise<GetQuizScoresResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
return await CoursesInstructorService.getQuizScores({
|
||||
token,
|
||||
course_id: courseId,
|
||||
lesson_id: lessonId,
|
||||
page,
|
||||
limit,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ดูรายละเอียดการทำข้อสอบล่าสุดของนักเรียนแต่ละคน
|
||||
* Get latest quiz attempt detail for a specific student
|
||||
* @param courseId - รหัสคอร์ส / Course ID
|
||||
* @param lessonId - รหัสบทเรียน / Lesson ID
|
||||
* @param studentId - รหัสนักเรียน / Student ID
|
||||
*/
|
||||
@Get('{courseId}/lessons/{lessonId}/quiz/students/{studentId}')
|
||||
@Security('jwt', ['instructor'])
|
||||
@SuccessResponse('200', 'Quiz attempt detail retrieved successfully')
|
||||
@Response('401', 'Invalid or expired token')
|
||||
@Response('403', 'Not an instructor of this course')
|
||||
@Response('404', 'Student or quiz attempt not found')
|
||||
public async getQuizAttemptDetail(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Path() lessonId: number,
|
||||
@Path() studentId: number
|
||||
): Promise<GetQuizAttemptDetailResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
return await CoursesInstructorService.getQuizAttemptDetail({
|
||||
token,
|
||||
course_id: courseId,
|
||||
lesson_id: lessonId,
|
||||
student_id: studentId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ค้นหานักเรียนในคอร์ส
|
||||
* Search students in course by firstname, lastname, email, or username
|
||||
* @param courseId - รหัสคอร์ส / Course ID
|
||||
* @param query - คำค้นหา / Search query
|
||||
* @param limit - จำนวนผลลัพธ์สูงสุด / Max results
|
||||
*/
|
||||
@Get('{courseId}/students/search')
|
||||
@Security('jwt', ['instructor'])
|
||||
@SuccessResponse('200', 'Students found successfully')
|
||||
@Response('401', 'Invalid or expired token')
|
||||
@Response('403', 'Not an instructor of this course')
|
||||
public async searchStudents(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Query() query: string,
|
||||
@Query() limit?: number
|
||||
): Promise<SearchStudentsResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) throw new ValidationError('No token provided');
|
||||
return await CoursesInstructorService.searchStudentsInCourse({
|
||||
token,
|
||||
course_id: courseId,
|
||||
query,
|
||||
limit,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import {
|
|||
CompleteLessonResponse,
|
||||
SubmitQuizResponse,
|
||||
SubmitQuizBody,
|
||||
GetQuizAttemptsResponse,
|
||||
} from '../types/CoursesStudent.types';
|
||||
import { EnrollmentStatus } from '@prisma/client';
|
||||
|
||||
|
|
@ -234,4 +235,32 @@ export class CoursesStudentController {
|
|||
answers: body.answers,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ดึงคะแนน Quiz ที่เคยทำ
|
||||
* Get quiz attempts and scores for a lesson
|
||||
* @param courseId - รหัสคอร์ส / Course ID
|
||||
* @param lessonId - รหัสบทเรียน / Lesson ID
|
||||
*/
|
||||
@Get('courses/{courseId}/lessons/{lessonId}/quiz/attempts')
|
||||
@Security('jwt', ['student'])
|
||||
@SuccessResponse('200', 'Quiz attempts retrieved successfully')
|
||||
@Response('401', 'Invalid or expired token')
|
||||
@Response('403', 'Not enrolled in this course')
|
||||
@Response('404', 'Lesson or quiz not found')
|
||||
public async getQuizAttempts(
|
||||
@Request() request: any,
|
||||
@Path() courseId: number,
|
||||
@Path() lessonId: number
|
||||
): Promise<GetQuizAttemptsResponse> {
|
||||
const token = request.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) {
|
||||
throw new ValidationError('No token provided');
|
||||
}
|
||||
return await this.service.getQuizAttempts({
|
||||
token,
|
||||
course_id: courseId,
|
||||
lesson_id: lessonId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue