Source

API/src/controllers/coursesection.controllers.js

/**
 * @fileoverview Course section controller
 * 
 * @category Backend API
 * @subcategory Controllers
 * 
 * @module CourseSection Controller
 * @requires ../models/course.models
 * @requires ../utils/errors
 * 
 * @description This module is responsible for handling all course section related requests <br>
 * 
 * The following routes are handled by this module:: <br>
 * 
 * </br>
 * 
 * <b>POST</b> /coursesection/new <br>
 * <b>GET</b> /coursesection/:id <br>
 * <b>PATCH</b> /coursesection/update/:id <br>
 * <b>DELETE</b> /coursesection/delete/:id <br>
 */

const { Course, CourseSection, Video, Exercise } = require("../models/course.models");
const { translateDoc } = require("../utils/crowdin");
const { BadRequestError, NotFoundError, ForbiddenError } = require("../utils/errors");

/**
 * Create course section
 *
 * @description Create course section to group course contents
 *
 * @param {string} course_id - Id of course to add section to
 * @param {string} title - Title of course section
 *
 * @throws {BadRequestError} if missing param in request body
 * @throws {NotFoundError} if course not found
 *
 * @returns {Object}
 * @see {@link module:CourseModel~courseSectionSchema}
 */
exports.createCourseSection = async (req, res, next) => {
    const { course_id, title } = req.body;
    if (!course_id | !title) {
        return next(new BadRequestError("Missing required param in request body"));
    }

    const course = await Course.findById(course_id);
    if (!course) {
        return next(new NotFoundError("Course not found"));
    }

    const course_section = await CourseSection.create({
        title,
        course: course_id,
    });

    return res.status(200).send({
        success: true,
        data: {
            course_section,
        },
    });
};

/**
 * Get course section data
 *
 * @description Get all the contents of a course section, it includes videos, exercises and text materials
 * of the course section. An additional field `content` is also added, it is an array of objects, each object
 * contains the type of content and the content itself. The type of content can be either `video`, `exercise` or
 * `textmaterial`. The content itself is the object of the content.
 * These contents are sorted by the order they were added to the course section.
 * 
 * @see {@link module:CourseModel~courseSectionSchema}
 *
 * @param {string} id - Id of course section
 * @throws {BadRequestError} if missing param in request body
 * @throws {NotFoundError} if course section not found
 *
 * @returns {Object}
 */
exports.getCourseSectionData = async (req, res, next) => {
    const course_section_id = req.params.id;

    if (!course_section_id || course_section_id == ":id") {
        return next(new BadRequestError("Missing param `id` in request params"));
    }

    const course_section = await CourseSection.findById(
        course_section_id
    ).populate("videos exercises textmaterials");
    if (!course_section) {
        return next(new NotFoundError("Course section not found"));
    }

    return res.status(200).send({
        success: true,
        data: {
            course_section: await course_section.populate({
                path: "course", 
                select: "title description title_tr description_tr author _id",
            }),
        },
    });
};

/**
 * Update course section data
 *
 * @description Update contents of a course section
 *
 * @param {string} id - Id of course section
 * @param {object} req.body - content to update in coursesection
 * 
 * @throws {BadRequestError} if missing param in request body
 * @throws {NotFoundError} if course section not found
 *
 * @returns {Object}
 */
exports.updateCourseSection = async (req, res, next) => {
    const { title } = req.body
    const course_section_id = req.params.id

    if (!course_section_id || course_section_id == ":id") {
        return next(new BadRequestError("Missing param `id` in request params"));
    }

    const course_section = await CourseSection.findByIdAndUpdate(
        course_section_id, { title }, { new: true }
    ).populate("course videos exercises");
    if (!course_section) {
        return next(new NotFoundError("Course section not found"));
    }

    const updated_course_section = await translateDoc(course_section)

    return res.status(200).send({
        success: true,
        data: {
            course_section: course_section.toObject(),
        },
    });

};

// exports.hideCourseSection = async (req, res, next) => { };

// exports.showCourseSection = async (req, res, next) => { };

/**
 * Delete course section 
 *
 * @description Delete course section
 *
 * @param {string} id - Id of course section
 * 
 * @throws {BadRequestError} if missing param in request body
 * @throws {NotFoundError} if course section not found
 * @throws {ForbiddenError} if course section still has linked exercises
 * @throws {ForbiddenError} if course section still has linked videos 
 *
 * @returns {Object}
 */
exports.deleteCourseSection = async (req, res, next) => {
    const course_section_id = req.params.id

    if (!course_section_id || course_section_id == ":id") {
        return next(new BadRequestError("Missing param `id` in request params"));
    }

    const course_section = await CourseSection.findById(
        course_section_id).populate('videos exercises')

    if (!course_section) {
        return next(new NotFoundError('Course content not found'))
    }

    // Check if course section has linked exercises or videos
    // if yes, user should first delete the videos or exercise
    // or link them to another course section
    if (!course_section.exercises) {
        return next(new ForbiddenError('Course content still has linked exercises'))
    }

    if (!course_section.videos) {
        return next(new ForbiddenError('Course content still has linked videos'))
    }

    await course_section.deleteOne()

    return res.status(200).send({
        success: true,
        data: {
            message: 'Course content deleted successfully'
        }
    })
}