diff --git a/Backend/src/controllers/CoursesController.ts b/Backend/src/controllers/CoursesController.ts index 0803bdfd..dfaebeb1 100644 --- a/Backend/src/controllers/CoursesController.ts +++ b/Backend/src/controllers/CoursesController.ts @@ -12,12 +12,20 @@ export class CoursesController { * ดึงรายการคอร์สทั้งหมด (สามารถ filter ด้วย category_id ได้) * Get all courses (can filter by category_id) * @param category_id - รหัสหมวดหมู่ / Category ID (optional) + * @param page - หน้าที่ต้องการดึง / Page number (default: 1) + * @param limit - จำนวนรายการต่อหน้า / Items per page (default: 10) + * @param random - สุ่มลำดับคอร์ส / Randomize courses order (default: false) */ @Get() @SuccessResponse('200', 'Courses fetched successfully') @Response('401', 'Invalid or expired token') - public async listCourses(@Query() category_id?: number): Promise { - return await this.coursesService.ListCourses(category_id); + public async listCourses( + @Query() category_id?: number, + @Query() page?: number, + @Query() limit?: number, + @Query() random?: boolean + ): Promise { + return await this.coursesService.ListCourses({ category_id, page, limit, random }); } /** diff --git a/Backend/src/services/courses.service.ts b/Backend/src/services/courses.service.ts index 4d176c2c..af48c660 100644 --- a/Backend/src/services/courses.service.ts +++ b/Backend/src/services/courses.service.ts @@ -2,13 +2,15 @@ import { prisma } from '../config/database'; import { Prisma } from '@prisma/client'; import { config } from '../config'; import { logger } from '../config/logger'; -import { listCourseResponse, getCourseResponse } from '../types/courses.types'; +import { listCourseResponse, getCourseResponse, ListCoursesInput } from '../types/courses.types'; import { UnauthorizedError, ValidationError, ForbiddenError } from '../middleware/errorHandler'; import { getPresignedUrl } from '../config/minio'; export class CoursesService { - async ListCourses(category_id?: number): Promise { + async ListCourses(input: ListCoursesInput): Promise { try { + const { category_id, page = 1, limit = 10, random = false } = input; + const where: Prisma.CourseWhereInput = { status: 'APPROVED', }; @@ -17,7 +19,35 @@ export class CoursesService { where.category_id = category_id; } - const courses = await prisma.course.findMany({ where }); + // Get total count for pagination + const total = await prisma.course.count({ where }); + const totalPages = Math.ceil(total / limit); + + let courses; + + if (random) { + // Random mode: ดึงทั้งหมดแล้วสุ่ม + const allCourses = await prisma.course.findMany({ where }); + + // Fisher-Yates shuffle + for (let i = allCourses.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [allCourses[i], allCourses[j]] = [allCourses[j], allCourses[i]]; + } + + // Apply pagination after shuffle + const skip = (page - 1) * limit; + courses = allCourses.slice(skip, skip + limit); + } else { + // Normal mode: pagination with skip/take + const skip = (page - 1) * limit; + courses = await prisma.course.findMany({ + where, + skip, + take: limit, + orderBy: { created_at: 'desc' } + }); + } // Generate presigned URLs for thumbnails const coursesWithUrls = await Promise.all( @@ -40,7 +70,10 @@ export class CoursesService { return { code: 200, message: 'Courses fetched successfully', - total: coursesWithUrls.length, + total, + page, + limit, + totalPages, data: coursesWithUrls, }; } catch (error) { diff --git a/Backend/src/types/courses.types.ts b/Backend/src/types/courses.types.ts index b7696abd..c343564c 100644 --- a/Backend/src/types/courses.types.ts +++ b/Backend/src/types/courses.types.ts @@ -1,10 +1,20 @@ import { Course } from '@prisma/client'; +export interface ListCoursesInput { + category_id?: number; + page?: number; + limit?: number; + random?: boolean; +} + export interface listCourseResponse { code: number; message: string; data: Course[]; total: number; + page: number; + limit: number; + totalPages: number; } export interface getCourseResponse {