diff --git a/controllers/learningControllers/stdLearning.js b/controllers/learningControllers/stdLearning.js index 7d58292..8db2329 100644 --- a/controllers/learningControllers/stdLearning.js +++ b/controllers/learningControllers/stdLearning.js @@ -309,6 +309,7 @@ export const learningHistory = async (req, res) => { } return { + ID_STUDENT_LEARNING: learning.ID_STUDENT_LEARNING, SCORE: learning.SCORE, CURRENT_LEVEL: learning.level?.NAME_LEVEL || "No level", NEXT_LEVEL: nextLevelName, @@ -418,6 +419,7 @@ export const learningHistoryBySectionId = async (req, res) => { } return { + ID_STUDENT_LEARNING: learning.ID_STUDENT_LEARNING, SCORE: learning.SCORE, CURRENT_LEVEL: learning.level?.NAME_LEVEL || "No level", NEXT_LEVEL: nextLevelName, @@ -531,6 +533,7 @@ export const learningHistoryByTopicId = async (req, res) => { } return { + ID_STUDENT_LEARNING: learning.ID_STUDENT_LEARNING, SCORE: learning.SCORE, CURRENT_LEVEL: learning.level?.NAME_LEVEL || "No level", NEXT_LEVEL: nextLevelName, @@ -570,59 +573,111 @@ export const learningHistoryByTopicId = async (req, res) => { }; export const recentStudentActivities = async (req, res) => { + const { page = 1, limit = 5, search = "" } = req.query; + try { - const stdLearnings = await models.StdLearning.findAll({ - where: { - STUDENT_FINISH: { - [models.Sequelize.Op.ne]: null, - }, - SCORE: { - [models.Sequelize.Op.ne]: null, - }, - NEXT_LEARNING: { - [models.Sequelize.Op.ne]: null, - }, - }, - include: [ - { - model: models.User, - as: "learningUser", - attributes: ["ID", "NAME_USERS"], - include: [ - { - model: models.Student, - as: "students", - attributes: ["NISN"], - }, - ], - }, - { - model: models.Level, - as: "level", - attributes: ["NAME_LEVEL"], - include: [ - { - model: models.Topic, - as: "levelTopic", - attributes: ["NAME_TOPIC"], - include: [ - { - model: models.Section, - as: "topicSection", - attributes: ["NAME_SECTION"], + const { count, rows: stdLearnings } = + await models.StdLearning.findAndCountAll({ + where: { + STUDENT_FINISH: { + [models.Sequelize.Op.ne]: null, + }, + SCORE: { + [models.Sequelize.Op.ne]: null, + }, + NEXT_LEARNING: { + [models.Sequelize.Op.ne]: null, + }, + ...(search && { + [models.Sequelize.Op.or]: [ + { + SCORE: { + [models.Sequelize.Op.like]: `%${search}%`, }, - ], - }, - ], + }, + { + "$learningUser.NAME_USERS$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$learningUser.students.NISN$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$learningUser.students.studentClass.NAME_CLASS$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$level.levelTopic.topicSection.NAME_SECTION$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$level.levelTopic.NAME_TOPIC$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$level.NAME_LEVEL$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + ], + }), }, - ], - order: [["STUDENT_FINISH", "DESC"]], - limit: 5, - }); + include: [ + { + model: models.User, + as: "learningUser", + attributes: ["ID", "NAME_USERS"], + include: [ + { + model: models.Student, + as: "students", + attributes: ["NISN"], + include: [ + { + model: models.Class, + as: "studentClass", + attributes: ["NAME_CLASS"], + }, + ], + }, + ], + }, + { + model: models.Level, + as: "level", + attributes: ["NAME_LEVEL"], + include: [ + { + model: models.Topic, + as: "levelTopic", + attributes: ["NAME_TOPIC"], + include: [ + { + model: models.Section, + as: "topicSection", + attributes: ["NAME_SECTION"], + }, + ], + }, + ], + }, + ], + order: [["STUDENT_FINISH", "DESC"]], + distinct: true, + }); const recentActivities = stdLearnings.map((learning) => ({ + ID_STUDENT_LEARNING: learning.ID_STUDENT_LEARNING || "N/A", NISN: learning.learningUser?.students?.NISN || "N/A", NAME_USERS: learning.learningUser?.NAME_USERS || "N/A", + NAME_CLASS: + learning.learningUser?.students?.studentClass?.NAME_CLASS || null, NAME_SECTION: learning.level?.levelTopic?.topicSection?.NAME_SECTION || "N/A", NAME_TOPIC: learning.level?.levelTopic?.NAME_TOPIC || "N/A", @@ -634,10 +689,180 @@ export const recentStudentActivities = async (req, res) => { return res.status(404).json({ message: "No recent activities found" }); } - res.status(200).json({ recentActivities }); + const paginatedActivities = recentActivities.slice( + (page - 1) * limit, + page * limit + ); + + const totalPages = Math.ceil(count / limit); + const currentPage = parseInt(page); + + response( + 200, + { + studentActivities: paginatedActivities, + currentPage, + totalPages, + totalItems: count, + }, + "Recent student activities retrieved successfully", + res + ); } catch (error) { console.error(error); - res.status(500).json({ message: "Internal Server Error" }); + response(500, null, "Internal Server Error", res); + } +}; + +export const recentStudentActivitiesByClassId = async (req, res) => { + const { page = 1, limit = 5, search = "" } = req.query; + const { ID_CLASS } = req.body; + + try { + const classData = await models.Class.findByPk(ID_CLASS); + + if (!classData) { + return response(404, null, "Class not found", res); + } + + const { count, rows: stdLearnings } = + await models.StdLearning.findAndCountAll({ + where: { + STUDENT_FINISH: { + [models.Sequelize.Op.ne]: null, + }, + SCORE: { + [models.Sequelize.Op.ne]: null, + }, + NEXT_LEARNING: { + [models.Sequelize.Op.ne]: null, + }, + ...(ID_CLASS && { + "$learningUser.students.ID_CLASS$": ID_CLASS, + }), + ...(search && { + [models.Sequelize.Op.or]: [ + { + SCORE: { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$learningUser.NAME_USERS$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$learningUser.students.NISN$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$learningUser.students.studentClass.NAME_CLASS$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$level.levelTopic.topicSection.NAME_SECTION$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$level.levelTopic.NAME_TOPIC$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + { + "$level.NAME_LEVEL$": { + [models.Sequelize.Op.like]: `%${search}%`, + }, + }, + ], + }), + }, + include: [ + { + model: models.User, + as: "learningUser", + attributes: ["ID", "NAME_USERS"], + include: [ + { + model: models.Student, + as: "students", + attributes: ["NISN", "ID_CLASS"], + include: [ + { + model: models.Class, + as: "studentClass", + attributes: ["NAME_CLASS"], + }, + ], + }, + ], + }, + { + model: models.Level, + as: "level", + attributes: ["NAME_LEVEL"], + include: [ + { + model: models.Topic, + as: "levelTopic", + attributes: ["NAME_TOPIC"], + include: [ + { + model: models.Section, + as: "topicSection", + attributes: ["NAME_SECTION"], + }, + ], + }, + ], + }, + ], + order: [["STUDENT_FINISH", "DESC"]], + distinct: true, + }); + + const recentActivities = stdLearnings.map((learning) => ({ + ID_STUDENT_LEARNING: learning.ID_STUDENT_LEARNING || "N/A", + NISN: learning.learningUser?.students?.NISN || "N/A", + NAME_USERS: learning.learningUser?.NAME_USERS || "N/A", + NAME_CLASS: + learning.learningUser?.students?.studentClass?.NAME_CLASS || null, + NAME_SECTION: + learning.level?.levelTopic?.topicSection?.NAME_SECTION || "N/A", + NAME_TOPIC: learning.level?.levelTopic?.NAME_TOPIC || "N/A", + NAME_LEVEL: learning.level?.NAME_LEVEL || "N/A", + SCORE: learning.SCORE || "N/A", + })); + + if (!recentActivities.length) { + return res.status(404).json({ message: "No recent activities found" }); + } + + const paginatedActivities = recentActivities.slice( + (page - 1) * limit, + page * limit + ); + + const totalPages = Math.ceil(count / limit); + const currentPage = parseInt(page); + + response( + 200, + { + studentActivities: paginatedActivities, + currentPage, + totalPages, + totalItems: count, + }, + "Recent student activities retrieved successfully", + res + ); + } catch (error) { + console.error(error); + response(500, null, "Internal Server Error", res); } }; diff --git a/routes/learning/stdLearning.js b/routes/learning/stdLearning.js index ad8998d..26564a2 100644 --- a/routes/learning/stdLearning.js +++ b/routes/learning/stdLearning.js @@ -1,5 +1,5 @@ import express from "express"; -import { getStdLearnings, getStdLearningById, createStdLearning, updateStdLearningById, learningScoreByStdLearningId, learningHistory, learningHistoryBySectionId, learningHistoryByTopicId, recentStudentActivities, getLastCreatedStdLearningByLevelId } from "../../controllers/learningControllers/stdLearning.js"; +import { getStdLearnings, getStdLearningById, createStdLearning, updateStdLearningById, learningScoreByStdLearningId, learningHistory, learningHistoryBySectionId, learningHistoryByTopicId, recentStudentActivities, recentStudentActivitiesByClassId, getLastCreatedStdLearningByLevelId } from "../../controllers/learningControllers/stdLearning.js"; import { checkStdLearning } from "../../middlewares/checkStdLearning.js"; import { verifyLoginUser } from "../../middlewares/User/authUser.js"; @@ -9,6 +9,8 @@ router.get("/stdLearning", verifyLoginUser, getStdLearnings); router.get("/stdLearning/activities", verifyLoginUser, recentStudentActivities); +router.get("/stdLearning/activities/class", verifyLoginUser, recentStudentActivitiesByClassId); + router.get("/stdLearning/:id", verifyLoginUser, getStdLearningById); router.get("/stdLearning/score/:stdLearningId", verifyLoginUser, learningScoreByStdLearningId); diff --git a/routes/user/user.js b/routes/user/user.js index 0f7c637..ab95878 100644 --- a/routes/user/user.js +++ b/routes/user/user.js @@ -10,7 +10,7 @@ router.get("/user", verifyLoginUser, adminOnly, getUsers); router.get("/user/admin", verifyLoginUser, adminOnly, getAdmins); -router.get("/user/teacher", verifyLoginUser, adminOnly, getTeachers); +router.get("/user/teacher", verifyLoginUser, adminOrTeacherOnly, getTeachers); router.get("/user/student", verifyLoginUser, adminOrTeacherOnly, getStudents);