Spaces:
Running
Running
File size: 2,882 Bytes
6e13570 4c6b1e8 6e13570 4c6b1e8 6e13570 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 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 };
|