const Course = require("../models/Course"); /** * Public course catalogue listing — powers both the homepage "Our * Academy" preview and the full Academy page. Supports the category * filter, free-text search, and pagination the Academy page needs, * since the number of courses is expected to keep growing. * * Query params (all optional): * category - one of Course.CATEGORIES, exact match * search - matched against title/description (case-insensitive) * page - 1-indexed, default 1 * limit - default 12, capped at 50 to avoid huge unbounded responses */ async function listCourses(req, res, next) { try { const filter = req.user?.role === "admin" ? {} : { isPublished: true }; if (req.query.category) { filter.category = req.query.category; } if (req.query.search) { const escaped = req.query.search.trim().replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const pattern = new RegExp(escaped, "i"); filter.$or = [{ title: pattern }, { description: pattern }]; } const page = Math.max(1, parseInt(req.query.page, 10) || 1); const limit = Math.min(50, Math.max(1, parseInt(req.query.limit, 10) || 12)); const [courses, total] = await Promise.all([ Course.find(filter) .sort({ createdAt: 1 }) .skip((page - 1) * limit) .limit(limit), Course.countDocuments(filter), ]); res.json({ courses, total, page, pages: Math.max(1, Math.ceil(total / limit)) }); } catch (err) { next(err); } } async function getCourse(req, res, next) { try { const course = await Course.findById(req.params.id); if (!course) return res.status(404).json({ error: "Course not found." }); res.json({ course }); } catch (err) { next(err); } } async function createCourse(req, res, next) { try { const course = await Course.create(req.body); res.status(201).json({ course }); } catch (err) { if (err.code === 11000) return res.status(409).json({ error: "A course with this slug already exists." }); next(err); } } async function updateCourse(req, res, next) { try { const course = await Course.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true, }); if (!course) return res.status(404).json({ error: "Course not found." }); res.json({ course }); } catch (err) { next(err); } } async function deleteCourse(req, res, next) { try { const course = await Course.findByIdAndUpdate(req.params.id, { isPublished: false }, { new: true }); if (!course) return res.status(404).json({ error: "Course not found." }); res.json({ success: true }); } catch (err) { next(err); } } module.exports = { listCourses, getCourse, createCourse, updateCourse, deleteCourse };