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) {
return response(404, null, "Topic not found", res);
return res.status(404).json({ message: "Topic not found" });
}
const levels = await models.Level.findAll({
@ -121,11 +121,18 @@ export const getLevelsByTopicId = async (req, res) => {
{
model: models.StdLearning,
as: "stdLearning",
attributes: ["SCORE", "ID_STUDENT_LEARNING"],
attributes: [
"SCORE",
"ID_STUDENT_LEARNING",
"STUDENT_START",
"STUDENT_FINISH",
],
where: {
ID: ID,
},
required: false,
order: [["STUDENT_START", "DESC"]],
limit: 1,
},
{
model: models.Topic,
@ -165,10 +172,12 @@ export const getLevelsByTopicId = async (req, res) => {
const levelsWithScore = levels.map((level) => {
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 =
level.stdLearning.length > 0
? level.stdLearning[0].ID_STUDENT_LEARNING
level.stdLearning && level.stdLearning.length > 0
? level.stdLearning[0]?.ID_STUDENT_LEARNING
: null;
const levelJSON = level.toJSON();
@ -213,7 +222,7 @@ export const getLevelsByTopicId = async (req, res) => {
res.status(200).json({ message: "Success", data: responsePayload });
} catch (error) {
console.log(error);
console.error(error);
res.status(500).json({ message: "Internal Server Error" });
}
};
@ -236,14 +245,17 @@ export const createLevel = async (req, res, next) => {
clearFileBuffers({ AUDIO, IMAGE });
return response(400, null, "Topic is required", res);
}
const transaction = await models.db.transaction();
try {
const sectionWithTopic = await models.Topic.findOne({
where: { ID_SECTION, ID_TOPIC },
transaction,
});
if (!sectionWithTopic) {
clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(
400,
null,
@ -254,10 +266,12 @@ export const createLevel = async (req, res, next) => {
const existingLevel = await models.Level.findOne({
where: { NAME_LEVEL, ID_TOPIC },
transaction,
});
if (existingLevel) {
clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(
409,
null,
@ -266,7 +280,8 @@ export const createLevel = async (req, res, next) => {
);
}
const newLevel = await models.Level.create({
const newLevel = await models.Level.create(
{
NAME_LEVEL,
ID_SECTION,
ID_TOPIC,
@ -281,7 +296,9 @@ export const createLevel = async (req, res, next) => {
ROUTE_4: req.body.ROUTE_4,
ROUTE_5: req.body.ROUTE_5,
ROUTE_6: req.body.ROUTE_6,
});
},
{ transaction }
);
req.body.newLevelId = newLevel.ID_LEVEL;
@ -294,7 +311,9 @@ export const createLevel = async (req, res, next) => {
newLevel.AUDIO = audioFilename;
newLevel.IMAGE = imageFilename;
await newLevel.save();
await newLevel.save({ transaction });
await transaction.commit();
await updateOtherLevelsRoutes(req, res, next);
@ -302,6 +321,7 @@ export const createLevel = async (req, res, next) => {
} catch (error) {
console.log(error);
clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
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 transaction = await models.db.transaction();
try {
const level = await models.Level.findByPk(id);
const level = await models.Level.findByPk(id, { transaction });
if (!level) {
clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(404, null, "Level not found", res);
}
const sectionWithTopic = await models.Topic.findOne({
where: { ID_SECTION, ID_TOPIC },
transaction,
});
if (!sectionWithTopic) {
clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(
400,
null,
@ -341,10 +366,12 @@ export const updateLevelById = async (req, res, next) => {
ID_TOPIC,
ID_LEVEL: { [models.Sequelize.Op.ne]: id },
},
transaction,
});
if (existingLevel) {
clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(
409,
null,
@ -356,19 +383,12 @@ export const updateLevelById = async (req, res, next) => {
if (NAME_LEVEL) {
level.NAME_LEVEL = NAME_LEVEL;
if (NAME_LEVEL === "Level 1") {
level.IS_PRETEST = 1;
} else {
level.IS_PRETEST = 0;
}
level.IS_PRETEST = NAME_LEVEL === "Level 1" ? 1 : 0;
}
if (ID_SECTION) level.ID_SECTION = ID_SECTION;
if (ID_TOPIC) level.ID_TOPIC = ID_TOPIC;
if (CONTENT) level.CONTENT = CONTENT;
if (VIDEO) {
level.VIDEO = VIDEO;
}
if (VIDEO) level.VIDEO = VIDEO;
if (AUDIO) {
if (level.AUDIO) {
@ -376,9 +396,7 @@ export const updateLevelById = async (req, res, next) => {
"public/uploads/level/audio",
level.AUDIO
);
if (fs.existsSync(oldAudioPath)) {
fs.unlinkSync(oldAudioPath);
}
if (fs.existsSync(oldAudioPath)) fs.unlinkSync(oldAudioPath);
}
level.AUDIO = saveFileToDisk(
AUDIO,
@ -395,9 +413,7 @@ export const updateLevelById = async (req, res, next) => {
"public/uploads/level/image",
level.IMAGE
);
if (fs.existsSync(oldImagePath)) {
fs.unlinkSync(oldImagePath);
}
if (fs.existsSync(oldImagePath)) fs.unlinkSync(oldImagePath);
}
level.IMAGE = saveFileToDisk(
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);
@ -418,6 +434,7 @@ export const updateLevelById = async (req, res, next) => {
} catch (error) {
console.log(error);
clearFileBuffers({ AUDIO, IMAGE });
await transaction.rollback();
return response(500, null, "Internal Server Error", res);
}
};
@ -471,11 +488,18 @@ export const getPreviousLevel = async (req, res) => {
{
model: models.StdLearning,
as: "stdLearning",
attributes: ["SCORE", "ID_STUDENT_LEARNING"],
attributes: [
"SCORE",
"ID_STUDENT_LEARNING",
"STUDENT_START",
"STUDENT_FINISH",
],
where: {
ID: ID,
},
required: false,
order: [["STUDENT_FINISH", "DESC"]],
limit: 1,
},
],
attributes: {
@ -491,14 +515,14 @@ export const getPreviousLevel = async (req, res) => {
});
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 levelNumber = parseInt(NAME_LEVEL.replace("Level ", ""));
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({
@ -534,21 +558,30 @@ export const getPreviousLevel = async (req, res) => {
{
model: models.StdLearning,
as: "stdLearning",
attributes: ["SCORE", "ID_STUDENT_LEARNING"],
attributes: [
"SCORE",
"ID_STUDENT_LEARNING",
"STUDENT_START",
"STUDENT_FINISH",
],
where: {
ID: ID,
},
required: false,
order: [["STUDENT_START", "DESC"]],
limit: 1,
},
],
});
const previousLevelsWithScore = previousLevels.map((level) => {
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 =
level.stdLearning.length > 0
? level.stdLearning[0].ID_STUDENT_LEARNING
level.stdLearning && level.stdLearning.length > 0
? level.stdLearning[0]?.ID_STUDENT_LEARNING
: null;
const levelJSON = level.toJSON();
@ -564,19 +597,19 @@ export const getPreviousLevel = async (req, res) => {
const currentLevelWithScore = {
...currentLevel.toJSON(),
ID_STUDENT_LEARNING:
currentLevel.stdLearning.length > 0
? currentLevel.stdLearning[0].ID_STUDENT_LEARNING
currentLevel.stdLearning && currentLevel.stdLearning.length > 0
? currentLevel.stdLearning[0]?.ID_STUDENT_LEARNING
: null,
SCORE:
currentLevel.stdLearning.length > 0
? currentLevel.stdLearning[0].SCORE
: 0,
currentLevel.stdLearning && currentLevel.stdLearning.length > 0
? currentLevel.stdLearning[0]?.SCORE
: null,
};
delete currentLevelWithScore.stdLearning;
if (!previousLevelsWithScore.length && !currentLevelWithScore) {
return response(404, null, "No levels found", res);
return res.status(404).json({ message: "No levels found" });
}
const result = {
@ -584,9 +617,9 @@ export const getPreviousLevel = async (req, res) => {
previousLevels: previousLevelsWithScore,
};
response(200, result, "Success", res);
res.status(200).json({ message: "Success", data: result });
} catch (error) {
console.log(error);
console.error(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) => {
const { NAME_SECTION, DESCRIPTION_SECTION } = req.body;
const { THUMBNAIL } = req.filesToSave || {};
if (!NAME_SECTION) {
@ -48,24 +47,46 @@ export const createSection = async (req, res) => {
return response(400, null, "Description is required", res);
}
const transaction = await models.db.transaction();
try {
const newSection = await models.Section.create({
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);
}
const newSection = await models.Section.create(
{
NAME_SECTION,
DESCRIPTION_SECTION,
THUMBNAIL: null,
});
},
{ transaction }
);
const thumbnailFilename = THUMBNAIL
? saveFileToDisk(THUMBNAIL, "THUMBNAIL", newSection.ID_SECTION)
: null;
newSection.THUMBNAIL = thumbnailFilename;
await newSection.save();
await newSection.save({ transaction });
await transaction.commit();
response(201, newSection, "Section created successfully", res);
} catch (error) {
console.log(error);
await transaction.rollback();
clearFileBuffers({ THUMBNAIL });
response(500, null, "Internal Server Error", res);
}
};
@ -73,18 +94,34 @@ export const createSection = async (req, res) => {
export const updateSectionById = async (req, res) => {
const { id } = req.params;
const { NAME_SECTION, DESCRIPTION_SECTION } = req.body;
const { THUMBNAIL } = req.filesToSave || {};
const transaction = await models.db.transaction();
try {
const section = await models.Section.findByPk(id);
const section = await models.Section.findByPk(id, { transaction });
if (!section) {
clearFileBuffers({ THUMBNAIL });
await transaction.rollback();
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 (THUMBNAIL) {
@ -97,6 +134,7 @@ export const updateSectionById = async (req, res) => {
fs.unlinkSync(oldThumbnailPath);
}
}
section.THUMBNAIL = saveFileToDisk(
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);
} catch (error) {
console.log(error);
await transaction.rollback();
clearFileBuffers({ THUMBNAIL });
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) => {
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 { 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 { updateStdLearningById } from "../../controllers/learningControllers/stdLearning.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("/studentAnswers/:id", verifyLoginUser, getStudentAnswersByStdLearningId);
export default router