refactor: stdExercise and level model

This commit is contained in:
elangptra 2024-10-01 15:03:44 +07:00
parent dfe4ab12d0
commit eedafb036f
8 changed files with 207 additions and 69 deletions

View File

@ -100,7 +100,7 @@ export const getLevelsByTopicId = async (req, res) => {
}); });
if (!topicExists) { if (!topicExists) {
return response(404, null, "Topic not found", res); return res.status(404).json({ message: "Topic not found" });
} }
const levels = await models.Level.findAll({ const levels = await models.Level.findAll({
@ -121,11 +121,18 @@ export const getLevelsByTopicId = async (req, res) => {
{ {
model: models.StdLearning, model: models.StdLearning,
as: "stdLearning", as: "stdLearning",
attributes: ["SCORE", "ID_STUDENT_LEARNING"], attributes: [
"SCORE",
"ID_STUDENT_LEARNING",
"STUDENT_START",
"STUDENT_FINISH",
],
where: { where: {
ID: ID, ID: ID,
}, },
required: false, required: false,
order: [["STUDENT_START", "DESC"]],
limit: 1,
}, },
{ {
model: models.Topic, model: models.Topic,
@ -165,10 +172,12 @@ export const getLevelsByTopicId = async (req, res) => {
const levelsWithScore = levels.map((level) => { const levelsWithScore = levels.map((level) => {
const SCORE = const SCORE =
level.stdLearning.length > 0 ? level.stdLearning[0].SCORE : 0; level.stdLearning && level.stdLearning.length > 0
? level.stdLearning[0]?.SCORE
: null;
const ID_STUDENT_LEARNING = const ID_STUDENT_LEARNING =
level.stdLearning.length > 0 level.stdLearning && level.stdLearning.length > 0
? level.stdLearning[0].ID_STUDENT_LEARNING ? level.stdLearning[0]?.ID_STUDENT_LEARNING
: null; : null;
const levelJSON = level.toJSON(); const levelJSON = level.toJSON();
@ -213,7 +222,7 @@ export const getLevelsByTopicId = async (req, res) => {
res.status(200).json({ message: "Success", data: responsePayload }); res.status(200).json({ message: "Success", data: responsePayload });
} catch (error) { } catch (error) {
console.log(error); console.error(error);
res.status(500).json({ message: "Internal Server Error" }); res.status(500).json({ message: "Internal Server Error" });
} }
}; };
@ -236,14 +245,17 @@ export const createLevel = async (req, res, next) => {
clearFileBuffers({ AUDIO, IMAGE }); clearFileBuffers({ AUDIO, IMAGE });
return response(400, null, "Topic is required", res); return response(400, null, "Topic is required", res);
} }
const transaction = await models.db.transaction();
try { try {
const sectionWithTopic = await models.Topic.findOne({ const sectionWithTopic = await models.Topic.findOne({
where: { ID_SECTION, ID_TOPIC }, where: { ID_SECTION, ID_TOPIC },
transaction,
}); });
if (!sectionWithTopic) { if (!sectionWithTopic) {
clearFileBuffers({ AUDIO, IMAGE }); clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response( return response(
400, 400,
null, null,
@ -254,10 +266,12 @@ export const createLevel = async (req, res, next) => {
const existingLevel = await models.Level.findOne({ const existingLevel = await models.Level.findOne({
where: { NAME_LEVEL, ID_TOPIC }, where: { NAME_LEVEL, ID_TOPIC },
transaction,
}); });
if (existingLevel) { if (existingLevel) {
clearFileBuffers({ AUDIO, IMAGE }); clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response( return response(
409, 409,
null, null,
@ -266,22 +280,25 @@ export const createLevel = async (req, res, next) => {
); );
} }
const newLevel = await models.Level.create({ const newLevel = await models.Level.create(
NAME_LEVEL, {
ID_SECTION, NAME_LEVEL,
ID_TOPIC, ID_SECTION,
IS_PRETEST: req.body.IS_PRETEST || 0, ID_TOPIC,
CONTENT, IS_PRETEST: req.body.IS_PRETEST || 0,
VIDEO: VIDEO || null, CONTENT,
AUDIO: null, VIDEO: VIDEO || null,
IMAGE: null, AUDIO: null,
ROUTE_1: req.body.ROUTE_1, IMAGE: null,
ROUTE_2: req.body.ROUTE_2, ROUTE_1: req.body.ROUTE_1,
ROUTE_3: req.body.ROUTE_3, ROUTE_2: req.body.ROUTE_2,
ROUTE_4: req.body.ROUTE_4, ROUTE_3: req.body.ROUTE_3,
ROUTE_5: req.body.ROUTE_5, ROUTE_4: req.body.ROUTE_4,
ROUTE_6: req.body.ROUTE_6, ROUTE_5: req.body.ROUTE_5,
}); ROUTE_6: req.body.ROUTE_6,
},
{ transaction }
);
req.body.newLevelId = newLevel.ID_LEVEL; req.body.newLevelId = newLevel.ID_LEVEL;
@ -294,7 +311,9 @@ export const createLevel = async (req, res, next) => {
newLevel.AUDIO = audioFilename; newLevel.AUDIO = audioFilename;
newLevel.IMAGE = imageFilename; newLevel.IMAGE = imageFilename;
await newLevel.save(); await newLevel.save({ transaction });
await transaction.commit();
await updateOtherLevelsRoutes(req, res, next); await updateOtherLevelsRoutes(req, res, next);
@ -302,6 +321,7 @@ export const createLevel = async (req, res, next) => {
} catch (error) { } catch (error) {
console.log(error); console.log(error);
clearFileBuffers({ AUDIO, IMAGE }); clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(500, null, "Internal Server Error", res); return response(500, null, "Internal Server Error", res);
} }
}; };
@ -312,20 +332,25 @@ export const updateLevelById = async (req, res, next) => {
const { AUDIO, IMAGE } = req.filesToSave || {}; const { AUDIO, IMAGE } = req.filesToSave || {};
const transaction = await models.db.transaction();
try { try {
const level = await models.Level.findByPk(id); const level = await models.Level.findByPk(id, { transaction });
if (!level) { if (!level) {
clearFileBuffers({ AUDIO, IMAGE }); clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(404, null, "Level not found", res); return response(404, null, "Level not found", res);
} }
const sectionWithTopic = await models.Topic.findOne({ const sectionWithTopic = await models.Topic.findOne({
where: { ID_SECTION, ID_TOPIC }, where: { ID_SECTION, ID_TOPIC },
transaction,
}); });
if (!sectionWithTopic) { if (!sectionWithTopic) {
clearFileBuffers({ AUDIO, IMAGE }); clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response( return response(
400, 400,
null, null,
@ -341,10 +366,12 @@ export const updateLevelById = async (req, res, next) => {
ID_TOPIC, ID_TOPIC,
ID_LEVEL: { [models.Sequelize.Op.ne]: id }, ID_LEVEL: { [models.Sequelize.Op.ne]: id },
}, },
transaction,
}); });
if (existingLevel) { if (existingLevel) {
clearFileBuffers({ AUDIO, IMAGE }); clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response( return response(
409, 409,
null, null,
@ -356,19 +383,12 @@ export const updateLevelById = async (req, res, next) => {
if (NAME_LEVEL) { if (NAME_LEVEL) {
level.NAME_LEVEL = NAME_LEVEL; level.NAME_LEVEL = NAME_LEVEL;
if (NAME_LEVEL === "Level 1") { level.IS_PRETEST = NAME_LEVEL === "Level 1" ? 1 : 0;
level.IS_PRETEST = 1;
} else {
level.IS_PRETEST = 0;
}
} }
if (ID_SECTION) level.ID_SECTION = ID_SECTION; if (ID_SECTION) level.ID_SECTION = ID_SECTION;
if (ID_TOPIC) level.ID_TOPIC = ID_TOPIC; if (ID_TOPIC) level.ID_TOPIC = ID_TOPIC;
if (CONTENT) level.CONTENT = CONTENT; if (CONTENT) level.CONTENT = CONTENT;
if (VIDEO) level.VIDEO = VIDEO;
if (VIDEO) {
level.VIDEO = VIDEO;
}
if (AUDIO) { if (AUDIO) {
if (level.AUDIO) { if (level.AUDIO) {
@ -376,9 +396,7 @@ export const updateLevelById = async (req, res, next) => {
"public/uploads/level/audio", "public/uploads/level/audio",
level.AUDIO level.AUDIO
); );
if (fs.existsSync(oldAudioPath)) { if (fs.existsSync(oldAudioPath)) fs.unlinkSync(oldAudioPath);
fs.unlinkSync(oldAudioPath);
}
} }
level.AUDIO = saveFileToDisk( level.AUDIO = saveFileToDisk(
AUDIO, AUDIO,
@ -395,9 +413,7 @@ export const updateLevelById = async (req, res, next) => {
"public/uploads/level/image", "public/uploads/level/image",
level.IMAGE level.IMAGE
); );
if (fs.existsSync(oldImagePath)) { if (fs.existsSync(oldImagePath)) fs.unlinkSync(oldImagePath);
fs.unlinkSync(oldImagePath);
}
} }
level.IMAGE = saveFileToDisk( level.IMAGE = saveFileToDisk(
IMAGE, IMAGE,
@ -408,9 +424,9 @@ export const updateLevelById = async (req, res, next) => {
); );
} }
await level.save(); await level.save({ transaction });
req.body.newLevelId = level.ID_LEVEL; await transaction.commit();
await updateOtherLevelsRoutes(req, res, next); await updateOtherLevelsRoutes(req, res, next);
@ -418,6 +434,7 @@ export const updateLevelById = async (req, res, next) => {
} catch (error) { } catch (error) {
console.log(error); console.log(error);
clearFileBuffers({ AUDIO, IMAGE }); clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(500, null, "Internal Server Error", res); return response(500, null, "Internal Server Error", res);
} }
}; };
@ -471,11 +488,18 @@ export const getPreviousLevel = async (req, res) => {
{ {
model: models.StdLearning, model: models.StdLearning,
as: "stdLearning", as: "stdLearning",
attributes: ["SCORE", "ID_STUDENT_LEARNING"], attributes: [
"SCORE",
"ID_STUDENT_LEARNING",
"STUDENT_START",
"STUDENT_FINISH",
],
where: { where: {
ID: ID, ID: ID,
}, },
required: false, required: false,
order: [["STUDENT_FINISH", "DESC"]],
limit: 1,
}, },
], ],
attributes: { attributes: {
@ -491,14 +515,14 @@ export const getPreviousLevel = async (req, res) => {
}); });
if (!currentLevel) { if (!currentLevel) {
return response(404, null, "Level not found", res); return res.status(404).json({ message: "Level not found" });
} }
const { NAME_LEVEL, ID_TOPIC } = currentLevel; const { NAME_LEVEL, ID_TOPIC } = currentLevel;
const levelNumber = parseInt(NAME_LEVEL.replace("Level ", "")); const levelNumber = parseInt(NAME_LEVEL.replace("Level ", ""));
if (isNaN(levelNumber)) { if (isNaN(levelNumber)) {
return response(400, null, "Invalid level format", res); return res.status(400).json({ message: "Invalid level format" });
} }
const previousLevels = await models.Level.findAll({ const previousLevels = await models.Level.findAll({
@ -534,21 +558,30 @@ export const getPreviousLevel = async (req, res) => {
{ {
model: models.StdLearning, model: models.StdLearning,
as: "stdLearning", as: "stdLearning",
attributes: ["SCORE", "ID_STUDENT_LEARNING"], attributes: [
"SCORE",
"ID_STUDENT_LEARNING",
"STUDENT_START",
"STUDENT_FINISH",
],
where: { where: {
ID: ID, ID: ID,
}, },
required: false, required: false,
order: [["STUDENT_START", "DESC"]],
limit: 1,
}, },
], ],
}); });
const previousLevelsWithScore = previousLevels.map((level) => { const previousLevelsWithScore = previousLevels.map((level) => {
const SCORE = const SCORE =
level.stdLearning.length > 0 ? level.stdLearning[0].SCORE : 0; level.stdLearning && level.stdLearning.length > 0
? level.stdLearning[0]?.SCORE
: null;
const ID_STUDENT_LEARNING = const ID_STUDENT_LEARNING =
level.stdLearning.length > 0 level.stdLearning && level.stdLearning.length > 0
? level.stdLearning[0].ID_STUDENT_LEARNING ? level.stdLearning[0]?.ID_STUDENT_LEARNING
: null; : null;
const levelJSON = level.toJSON(); const levelJSON = level.toJSON();
@ -564,19 +597,19 @@ export const getPreviousLevel = async (req, res) => {
const currentLevelWithScore = { const currentLevelWithScore = {
...currentLevel.toJSON(), ...currentLevel.toJSON(),
ID_STUDENT_LEARNING: ID_STUDENT_LEARNING:
currentLevel.stdLearning.length > 0 currentLevel.stdLearning && currentLevel.stdLearning.length > 0
? currentLevel.stdLearning[0].ID_STUDENT_LEARNING ? currentLevel.stdLearning[0]?.ID_STUDENT_LEARNING
: null, : null,
SCORE: SCORE:
currentLevel.stdLearning.length > 0 currentLevel.stdLearning && currentLevel.stdLearning.length > 0
? currentLevel.stdLearning[0].SCORE ? currentLevel.stdLearning[0]?.SCORE
: 0, : null,
}; };
delete currentLevelWithScore.stdLearning; delete currentLevelWithScore.stdLearning;
if (!previousLevelsWithScore.length && !currentLevelWithScore) { if (!previousLevelsWithScore.length && !currentLevelWithScore) {
return response(404, null, "No levels found", res); return res.status(404).json({ message: "No levels found" });
} }
const result = { const result = {
@ -584,9 +617,9 @@ export const getPreviousLevel = async (req, res) => {
previousLevels: previousLevelsWithScore, previousLevels: previousLevelsWithScore,
}; };
response(200, result, "Success", res); res.status(200).json({ message: "Success", data: result });
} catch (error) { } catch (error) {
console.log(error); console.error(error);
res.status(500).json({ message: "Internal Server Error" }); res.status(500).json({ message: "Internal Server Error" });
} }
}; };

View File

@ -35,7 +35,6 @@ export const getSectionById = async (req, res) => {
export const createSection = async (req, res) => { export const createSection = async (req, res) => {
const { NAME_SECTION, DESCRIPTION_SECTION } = req.body; const { NAME_SECTION, DESCRIPTION_SECTION } = req.body;
const { THUMBNAIL } = req.filesToSave || {}; const { THUMBNAIL } = req.filesToSave || {};
if (!NAME_SECTION) { if (!NAME_SECTION) {
@ -48,24 +47,46 @@ export const createSection = async (req, res) => {
return response(400, null, "Description is required", res); return response(400, null, "Description is required", res);
} }
const transaction = await models.db.transaction();
try { try {
const newSection = await models.Section.create({ const existingSection = await models.Section.findOne({
NAME_SECTION, where: { NAME_SECTION },
DESCRIPTION_SECTION, transaction,
THUMBNAIL: null,
}); });
if (existingSection) {
clearFileBuffers({ THUMBNAIL });
await transaction.rollback();
return response(400, null, "Section name already exists", res);
}
const newSection = await models.Section.create(
{
NAME_SECTION,
DESCRIPTION_SECTION,
THUMBNAIL: null,
},
{ transaction }
);
const thumbnailFilename = THUMBNAIL const thumbnailFilename = THUMBNAIL
? saveFileToDisk(THUMBNAIL, "THUMBNAIL", newSection.ID_SECTION) ? saveFileToDisk(THUMBNAIL, "THUMBNAIL", newSection.ID_SECTION)
: null; : null;
newSection.THUMBNAIL = thumbnailFilename; newSection.THUMBNAIL = thumbnailFilename;
await newSection.save();
await newSection.save({ transaction });
await transaction.commit();
response(201, newSection, "Section created successfully", res); response(201, newSection, "Section created successfully", res);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
await transaction.rollback();
clearFileBuffers({ THUMBNAIL }); clearFileBuffers({ THUMBNAIL });
response(500, null, "Internal Server Error", res); response(500, null, "Internal Server Error", res);
} }
}; };
@ -73,18 +94,34 @@ export const createSection = async (req, res) => {
export const updateSectionById = async (req, res) => { export const updateSectionById = async (req, res) => {
const { id } = req.params; const { id } = req.params;
const { NAME_SECTION, DESCRIPTION_SECTION } = req.body; const { NAME_SECTION, DESCRIPTION_SECTION } = req.body;
const { THUMBNAIL } = req.filesToSave || {}; const { THUMBNAIL } = req.filesToSave || {};
const transaction = await models.db.transaction();
try { try {
const section = await models.Section.findByPk(id); const section = await models.Section.findByPk(id, { transaction });
if (!section) { if (!section) {
clearFileBuffers({ THUMBNAIL }); clearFileBuffers({ THUMBNAIL });
await transaction.rollback();
return response(404, null, "Section not found", res); return response(404, null, "Section not found", res);
} }
if (NAME_SECTION) section.NAME_SECTION = NAME_SECTION; if (NAME_SECTION && NAME_SECTION !== section.NAME_SECTION) {
const existingSection = await models.Section.findOne({
where: { NAME_SECTION },
transaction,
});
if (existingSection) {
clearFileBuffers({ THUMBNAIL });
await transaction.rollback();
return response(400, null, "Section name already exists", res);
}
section.NAME_SECTION = NAME_SECTION;
}
if (DESCRIPTION_SECTION) section.DESCRIPTION_SECTION = DESCRIPTION_SECTION; if (DESCRIPTION_SECTION) section.DESCRIPTION_SECTION = DESCRIPTION_SECTION;
if (THUMBNAIL) { if (THUMBNAIL) {
@ -97,6 +134,7 @@ export const updateSectionById = async (req, res) => {
fs.unlinkSync(oldThumbnailPath); fs.unlinkSync(oldThumbnailPath);
} }
} }
section.THUMBNAIL = saveFileToDisk( section.THUMBNAIL = saveFileToDisk(
THUMBNAIL, THUMBNAIL,
"THUMBNAIL", "THUMBNAIL",
@ -104,12 +142,17 @@ export const updateSectionById = async (req, res) => {
); );
} }
await section.save(); await section.save({ transaction });
await transaction.commit();
response(200, section, "Section updated successfully", res); response(200, section, "Section updated successfully", res);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
await transaction.rollback();
clearFileBuffers({ THUMBNAIL }); clearFileBuffers({ THUMBNAIL });
response(500, null, "Internal Server Error", res); response(500, null, "Internal Server Error", res);
} }
}; };

View File

@ -100,5 +100,65 @@ export const stdAnswerExercise = async (req, res, next) => {
}; };
export const getStudentAnswersByStdLearningId = async (req, res) => { export const getStudentAnswersByStdLearningId = async (req, res) => {
try {
} const { id } = req.params;
const stdLearning = await models.StdLearning.findByPk(id, {
include: [
{
model: models.StdExercise,
as: "stdExercises",
include: [
{
model: models.Exercise,
as: "stdExerciseExercises",
attributes: ["ID_ADMIN_EXERCISE", "TITLE", "QUESTION", "QUESTION_TYPE"],
},
],
attributes: [
"ID_STUDENT_EXERCISE",
"ANSWER_STUDENT",
"IS_CORRECT",
"RESULT_SCORE_STUDENT",
"TIME_STUDENT_EXC",
],
},
],
attributes: ["ID_STUDENT_LEARNING", "ID_LEVEL", "SCORE", "IS_PASS"],
});
if (!stdLearning) {
return res.status(404).json({
message: "Student learning data not found",
});
}
const sortedExercises = stdLearning.stdExercises.sort((a, b) => {
const titleA = a.stdExerciseExercises.TITLE.toUpperCase();
const titleB = b.stdExerciseExercises.TITLE.toUpperCase();
if (titleA < titleB) return -1;
if (titleA > titleB) return 1;
return 0;
});
const mappedExercises = sortedExercises.map((exercise) => ({
...exercise.toJSON(),
exerciseDetails: exercise.stdExerciseExercises,
stdExerciseExercises: undefined,
}));
return res.status(200).json({
message: "Student learning exercises retrieved successfully",
data: {
...stdLearning.toJSON(),
stdExercises: mappedExercises,
},
});
} catch (error) {
console.error(error);
return res.status(500).json({
message: "Error retrieving student learning exercises",
});
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@ -1,5 +1,5 @@
import express from "express"; import express from "express";
import { getStdExercises, getStdExerciseById, stdAnswerExercise } from "../../controllers/learningControllers/stdExercise.js"; import { getStdExercises, getStdExerciseById, stdAnswerExercise, getStudentAnswersByStdLearningId } from "../../controllers/learningControllers/stdExercise.js";
import { verifyLoginUser } from "../../middlewares/User/authUser.js"; import { verifyLoginUser } from "../../middlewares/User/authUser.js";
import { updateStdLearningById } from "../../controllers/learningControllers/stdLearning.js"; import { updateStdLearningById } from "../../controllers/learningControllers/stdLearning.js";
import { checkCorrectAnswers, calculateScore, checkFirstFiveCorrect, nextLearning } from "../../middlewares/autoGrading.js"; import { checkCorrectAnswers, calculateScore, checkFirstFiveCorrect, nextLearning } from "../../middlewares/autoGrading.js";
@ -12,4 +12,6 @@ router.get("/stdExercise/:id", verifyLoginUser, getStdExerciseById);
router.post("/stdExercise", verifyLoginUser, stdAnswerExercise, checkCorrectAnswers, calculateScore, checkFirstFiveCorrect, nextLearning, updateStdLearningById); router.post("/stdExercise", verifyLoginUser, stdAnswerExercise, checkCorrectAnswers, calculateScore, checkFirstFiveCorrect, nextLearning, updateStdLearningById);
router.post("/studentAnswers/:id", verifyLoginUser, getStudentAnswersByStdLearningId);
export default router export default router