backend_adaptive_learning/middlewares/autoGrading.js

292 lines
8.3 KiB
JavaScript
Raw Normal View History

2024-09-13 13:03:35 +00:00
import models from "../models/index.js";
import response from "../response.js";
export const checkCorrectAnswers = async (req, res, next) => {
const { id } = req.params;
try {
const stdExercises = await models.StdExercise.findAll({
where: { ID_STUDENT_LEARNING: id },
});
if (!stdExercises || stdExercises.length === 0) {
return response(404, null, "No student exercises found", res);
}
for (const stdExercise of stdExercises) {
const { ID_ADMIN_EXERCISE, ANSWER_STUDENT } = stdExercise;
const exercise = await models.Exercise.findByPk(ID_ADMIN_EXERCISE);
if (!exercise) continue;
const weight = parseFloat(exercise.SCORE_WEIGHT);
2024-09-13 13:03:35 +00:00
const questionType = exercise.QUESTION_TYPE;
switch (questionType) {
case "MCQ": {
const multipleChoice = await models.MultipleChoices.findOne({
where: { ID_ADMIN_EXERCISE },
});
if (multipleChoice) {
stdExercise.IS_CORRECT =
ANSWER_STUDENT === multipleChoice.ANSWER_KEY ? 1 : 0;
stdExercise.RESULT_SCORE_STUDENT =
ANSWER_STUDENT === multipleChoice.ANSWER_KEY ? weight : 0.0;
}
break;
}
case "TFQ": {
const trueFalse = await models.TrueFalse.findOne({
where: { ID_ADMIN_EXERCISE },
});
if (trueFalse) {
const isTrueStudent = ANSWER_STUDENT === "1";
stdExercise.IS_CORRECT =
isTrueStudent === Boolean(trueFalse.IS_TRUE) ? 1 : 0;
stdExercise.RESULT_SCORE_STUDENT =
isTrueStudent === Boolean(trueFalse.IS_TRUE) ? weight : 0.0;
}
break;
}
case "MPQ": {
const matchingPairs = await models.MatchingPairs.findAll({
where: { ID_ADMIN_EXERCISE },
});
if (matchingPairs && matchingPairs.length > 0) {
2024-12-02 07:51:01 +00:00
const studentAnswers = ANSWER_STUDENT.split("|").map((pair) => {
const [left, right] = pair.split(">");
2024-09-13 13:03:35 +00:00
return {
LEFT_PAIR: left ? left.trim() : "",
RIGHT_PAIR: right ? right.trim() : "",
};
});
let correctCount = 0;
for (const studentAnswer of studentAnswers) {
if (
matchingPairs.some(
(pair) =>
pair.LEFT_PAIR === studentAnswer.LEFT_PAIR &&
pair.RIGHT_PAIR === studentAnswer.RIGHT_PAIR
)
) {
correctCount++;
}
}
const correctPercentage = correctCount / matchingPairs.length;
stdExercise.IS_CORRECT = correctCount > 0 ? 1 : 0;
stdExercise.RESULT_SCORE_STUDENT = correctPercentage * weight;
2024-09-13 13:03:35 +00:00
}
break;
}
default:
break;
}
await stdExercise.save();
}
next();
} catch (error) {
console.error("Error checking correct answers:", error);
response(500, null, "Internal Server Error", res);
}
};
export const calculateScore = async (req, res, next) => {
const { id } = req.params;
try {
const stdLearning = await models.StdLearning.findByPk(id);
if (!stdLearning) {
return response(404, null, "Student Learning record not found", res);
}
const allExercises = await models.Exercise.findAll({
where: {
ID_LEVEL: stdLearning.ID_LEVEL,
IS_DELETED: 0,
},
2024-09-13 13:03:35 +00:00
});
if (!allExercises || allExercises.length === 0) {
return response(404, null, "No exercises found for this level", res);
}
const stdExercises = await models.StdExercise.findAll({
where: { ID_STUDENT_LEARNING: id },
});
let totalWeight = 0;
for (const exercise of allExercises) {
totalWeight += exercise.SCORE_WEIGHT;
}
let totalScore = 0;
for (const stdExercise of stdExercises) {
const exercise = allExercises.find(
(ex) => ex.ID_ADMIN_EXERCISE === stdExercise.ID_ADMIN_EXERCISE
);
if (exercise && stdExercise.RESULT_SCORE_STUDENT !== null) {
totalScore += stdExercise.RESULT_SCORE_STUDENT;
}
}
const finalScore = Math.round((totalScore / totalWeight) * 100);
req.body.SCORE = finalScore;
next();
} catch (error) {
console.log(error);
response(500, null, "Internal Server Error", res);
}
};
export const checkFirstFiveCorrect = async (req, res, next) => {
const { id } = req.params;
try {
const stdLearning = await models.StdLearning.findByPk(id);
if (!stdLearning) {
return response(404, null, "Student Learning record not found", res);
}
const firstFiveExercises = await models.Exercise.findAll({
where: {
ID_LEVEL: stdLearning.ID_LEVEL,
IS_DELETED: 0,
},
2024-10-18 07:24:10 +00:00
order: [
[
models.Sequelize.literal(
"CAST(SUBSTRING_INDEX(TITLE, ' ', -1) AS UNSIGNED)"
),
"ASC",
],
],
2024-09-13 13:03:35 +00:00
limit: 5,
});
if (!firstFiveExercises || firstFiveExercises.length < 5) {
return response(404, null, "Not enough exercises for this level", res);
}
const stdExercises = await models.StdExercise.findAll({
where: { ID_STUDENT_LEARNING: id },
});
const allCorrect = firstFiveExercises.every((exercise) => {
const stdExercise = stdExercises.find(
(se) => se.ID_ADMIN_EXERCISE === exercise.ID_ADMIN_EXERCISE
);
return stdExercise && stdExercise.IS_CORRECT === 1;
});
req.body.FIRST_FIVE_CORRECT = allCorrect;
next();
} catch (error) {
console.error("Error checking first five correct answers:", error);
res.status(500).json({ message: "Internal Server Error" });
}
};
export const nextLearning = async (req, res, next) => {
const { SCORE, FIRST_FIVE_CORRECT } = req.body;
try {
const stdLearning = await models.StdLearning.findByPk(req.params.id, {
include: [
{
model: models.Level,
as: "level",
},
],
});
if (!stdLearning) {
return response(404, null, "Student Learning record not found", res);
}
const topic_id = stdLearning.level.ID_TOPIC;
const levels = await models.Level.findAll({
where: {
ID_TOPIC: topic_id,
IS_DELETED: 0,
},
2024-09-13 13:03:35 +00:00
order: [["NAME_LEVEL", "ASC"]],
});
const levelMap = levels.reduce((map, level) => {
map[level.NAME_LEVEL] = level;
return map;
}, {});
let nextLearningLevel = null;
let currentLevelNumber = parseInt(
stdLearning.level.NAME_LEVEL.split(" ")[1]
);
if (stdLearning.level.IS_PRETEST) {
if (SCORE >= 0 && SCORE <= 50) {
nextLearningLevel = levelMap["Level 1"];
} else if (SCORE >= 51 && SCORE <= 60) {
nextLearningLevel = levelMap["Level 2"];
} else if (SCORE >= 61 && SCORE <= 70) {
nextLearningLevel = levelMap["Level 3"];
} else if (SCORE >= 71 && SCORE <= 80) {
nextLearningLevel = levelMap["Level 4"];
} else if (SCORE >= 81 && SCORE <= 90) {
nextLearningLevel = levelMap["Level 5"];
} else if (SCORE >= 91 && SCORE <= 100) {
nextLearningLevel = levelMap["Level 6"];
}
} else {
if (SCORE >= 75 && FIRST_FIVE_CORRECT) {
currentLevelNumber += SCORE >= 85 ? 2 : 1;
currentLevelNumber = Math.min(6, currentLevelNumber);
} else if (
(SCORE >= 75 && !FIRST_FIVE_CORRECT) ||
(SCORE >= 51 && SCORE <= 74)
) {
currentLevelNumber = currentLevelNumber;
} else if (SCORE >= 41 && SCORE <= 50) {
currentLevelNumber = Math.max(1, currentLevelNumber - 1);
} else if (SCORE >= 0 && SCORE <= 40) {
currentLevelNumber = Math.max(1, currentLevelNumber - 2);
}
currentLevelNumber = Math.max(1, Math.min(6, currentLevelNumber));
nextLearningLevel = levelMap[`Level ${currentLevelNumber}`];
}
if (!nextLearningLevel) {
return response(404, null, "Next learning level not found", res);
}
req.body.NEXT_LEARNING = nextLearningLevel.ID_LEVEL;
req.body.IS_PASS =
SCORE > 85 &&
stdLearning.level.NAME_LEVEL === "Level 6" &&
FIRST_FIVE_CORRECT
? 1
: 0;
next();
} catch (error) {
console.log(error);
response(500, null, "Error determining next learning path", res);
}
};