refactor: stdExercise and level model
This commit is contained in:
parent
dfe4ab12d0
commit
eedafb036f
|
|
@ -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" });
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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.
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.7 KiB |
|
|
@ -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
|
||||
Loading…
Reference in New Issue
Block a user