import response from "../../response.js"; import models from "../../models/index.js"; import { updateMonitoringClass } from "./monitoring.js"; export const getClasses = async (req, res) => { try { const classes = await models.Class.findAll(); response(200, classes, "Success", res); } catch (error) { console.log(error); response(500, null, "Error retrieving classes data!", res); } }; export const getClassById = async (req, res) => { try { const { id } = req.params; const classes = await models.Class.findByPk(id); if (!classes) { return response(404, null, "Class not found", res); } response(200, classes, "Success", res); } catch (error) { console.log(error); response(500, null, "Internal Server Error", res); } }; export const getClassForAdmin = async (req, res) => { const { page = 1, limit = 10, search = "", sort = "time" } = req.query; try { const { count, rows: classes } = await models.Class.findAndCountAll({ where: { ...(search && { [models.Op.or]: [ { NAME_CLASS: { [models.Op.like]: `%${search}%`, }, }, models.Sequelize.where( models.Sequelize.literal( `(SELECT COUNT(*) FROM student WHERE student.ID_CLASS = class.ID_CLASS)` ), { [models.Op.like]: `%${search}%`, } ), { TOTAL_STUDENT: { [models.Op.like]: `%${search}%`, }, }, ], }), }, attributes: [ "ID_CLASS", "NAME_CLASS", "TOTAL_STUDENT", "TIME_CLASS", [ models.Sequelize.literal( `(SELECT COUNT(*) FROM student WHERE student.ID_CLASS = class.ID_CLASS)` ), "STUDENTS", ], ], distinct: true, }); const formattedClasses = classes.map((classItem) => ({ ID_CLASS: classItem.ID_CLASS, NAME_CLASS: classItem.NAME_CLASS, STUDENTS: classItem.get("STUDENTS"), TOTAL_STUDENT: classItem.TOTAL_STUDENT, TIME_CLASS: classItem.TIME_CLASS, })); if (sort === "class") { formattedClasses.sort((a, b) => a.NAME_CLASS.localeCompare(b.NAME_CLASS)); } else if (sort === "total") { formattedClasses.sort((a, b) => a.TOTAL_STUDENT - b.TOTAL_STUDENT); } else if (sort === "students") { formattedClasses.sort((a, b) => a.STUDENTS - b.STUDENTS); } else { formattedClasses.sort( (a, b) => new Date(b.TIME_CLASS) - new Date(a.TIME_CLASS) ); } const paginatedClasses = formattedClasses.slice( (page - 1) * limit, page * limit ); const totalPages = Math.ceil(count / limit); const currentPage = parseInt(page); response( 200, { classes: paginatedClasses, currentPage, totalPages, totalItems: count, }, "Classes retrieved successfully", res ); } catch (error) { console.log(error); response(500, null, "Error retrieving classes data!", res); } }; export const createClass = async (req, res) => { const { NAME_CLASS, TOTAL_STUDENT } = req.body; if (!NAME_CLASS) { return response(400, null, "Class name is required", res); } if (!TOTAL_STUDENT) { return response(400, null, "Total student is required", res); } try { const existingClass = await models.Class.findOne({ where: { NAME_CLASS }, }); if (existingClass) { return response(400, null, "Class with this name already exists", res); } const newClass = await models.Class.create({ NAME_CLASS, TOTAL_STUDENT, }); response(201, newClass, "Class created successfully", res); } catch (error) { console.log(error); response(500, null, "Internal Server Error", res); } }; export const updateClassById = async (req, res) => { const { id } = req.params; const { NAME_CLASS, TOTAL_STUDENT } = req.body; try { const classes = await models.Class.findByPk(id); if (!classes) { return response(404, null, "Class not found", res); } if (NAME_CLASS && NAME_CLASS !== classes.NAME_CLASS) { const existingClass = await models.Class.findOne({ where: { NAME_CLASS }, }); if (existingClass) { return response(400, null, "Class with this name already exists", res); } classes.NAME_CLASS = NAME_CLASS; } if (TOTAL_STUDENT) { classes.TOTAL_STUDENT = TOTAL_STUDENT; } await classes.save(); response(200, classes, "Class updated successfully", res); } catch (error) { console.log(error); response(500, null, "Internal Server Error", res); } }; export const deleteClassById = async (req, res) => { const { id } = req.params; try { const classes = await models.Class.findByPk(id); if (!classes) { return response(404, null, "Class not found", res); } await models.Student.update( { ID_CLASS: null }, { where: { ID_CLASS: id }, } ); await models.Monitoring.update( { ID_CLASS: null }, { where: { ID_CLASS: id }, } ); await classes.destroy(); response( 200, null, "Class deleted successfully and related models updated", res ); } catch (error) { console.log(error); response(500, null, "Internal Server Error", res); } }; export const updateStudentClassByName = async (req, res) => { const { NAME_CLASS, STUDENTS } = req.body; if (!NAME_CLASS || !Array.isArray(STUDENTS) || STUDENTS.length === 0) { return response( 400, null, "Class name and students data are required", res ); } try { const classRecord = await models.Class.findOne({ where: { NAME_CLASS }, }); if (!classRecord) { return response(404, null, "Class not found", res); } const updateResults = []; let hasError = false; let successCount = 0; let failureCount = 0; for (const { NAME_USERS, NISN } of STUDENTS) { if (!NAME_USERS || !NISN) { updateResults.push({ NAME_USERS, NISN, error: "User name and NISN are required for each student", }); hasError = true; failureCount++; continue; } try { const student = await models.Student.findOne({ include: [ { model: models.User, as: "studentUser", where: { NAME_USERS }, }, ], where: { NISN }, }); if (!student) { updateResults.push({ NAME_USERS, NISN, error: "Student with the given name and NISN not found", }); hasError = true; failureCount++; continue; } if (student.ID_CLASS === classRecord.ID_CLASS) { updateResults.push({ NAME_USERS, NISN, error: "Student is already in the selected class", }); hasError = true; failureCount++; continue; } student.ID_CLASS = classRecord.ID_CLASS; await student.save(); const stdLearningRecords = await models.StdLearning.findAll({ where: { ID: student.ID }, include: [ { model: models.Level, as: "level", where: { NAME_LEVEL: "Level 6" }, }, ], }); const studentUpdateResults = []; for (const stdLearning of stdLearningRecords) { try { const result = await updateMonitoringClass({ ID_STUDENT_LEARNING: stdLearning.ID_STUDENT_LEARNING, ID_CLASS: classRecord.ID_CLASS, }); studentUpdateResults.push(result); } catch (error) { console.error("Error updating monitoring class:", error.message); studentUpdateResults.push({ error: error.message }); } } updateResults.push({ NAME_USERS, NISN, message: "Student's class and related monitoring updated successfully", studentUpdateResults, }); successCount++; } catch (error) { console.error("Error processing student:", error.message); updateResults.push({ NAME_USERS, NISN, error: "Error processing student", details: error.message, }); hasError = true; failureCount++; } } let responseMessage = ""; if (failureCount === STUDENTS.length) { responseMessage = "Failed to update all students."; } else if (successCount > 0 && failureCount > 0) { responseMessage = "Some students updated successfully, but there were errors with others."; } else if (successCount === STUDENTS.length) { responseMessage = "All students updated successfully."; } return response(200, { updateResults }, responseMessage, res); } catch (error) { console.error(error); response(500, null, "Internal Server Error", res); } }; export const getStudentsByClassId = async (req, res) => { try { const { classId } = req.params; const studentsInClass = await models.User.findAll({ where: { ROLE: "student", }, attributes: ["ID", "NAME_USERS", "EMAIL", "ROLE"], include: [ { model: models.Student, as: "students", attributes: ["NISN", "ID_CLASS"], include: [ { model: models.Class, as: "studentClass", attributes: ["NAME_CLASS"], }, ], where: { ID_CLASS: classId, }, }, ], raw: true, nest: true, }); const formattedStudents = studentsInClass.map((student) => ({ ID: student.ID, NAME_USERS: student.NAME_USERS, EMAIL: student.EMAIL, NISN: student.students.NISN, NAME_CLASS: student.students.studentClass.NAME_CLASS, ROLE: student.ROLE, })); response(200, formattedStudents, "Success", res); } catch (error) { console.log(error); response(500, null, "Error retrieving students by class ID", res); } }; export const getStudentsWithNoClass = async (req, res) => { try { const studentsWithoutClass = await models.User.findAll({ where: { ROLE: "student", }, attributes: ["ID", "NAME_USERS", "EMAIL", "ROLE"], include: [ { model: models.Student, as: "students", attributes: ["NISN", "ID_CLASS"], include: [ { model: models.Class, as: "studentClass", attributes: ["NAME_CLASS"], }, ], where: { ID_CLASS: null, }, }, ], raw: true, nest: true, }); const formattedStudents = studentsWithoutClass.map((student) => ({ ID: student.ID, NAME_USERS: student.NAME_USERS, EMAIL: student.EMAIL, NISN: student.students.NISN, NAME_CLASS: student.students.studentClass.NAME_CLASS, ROLE: student.ROLE, })); response(200, formattedStudents, "Success", res); } catch (error) { console.log(error); response(500, null, "Error retrieving students with no class", res); } };