417 lines
11 KiB
JavaScript
417 lines
11 KiB
JavaScript
import response from "../../response.js";
|
|
import models from "../../models/index.js";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
|
|
export const getExercises = async (req, res) => {
|
|
try {
|
|
const exercises = await models.Exercise.findAll({
|
|
include: [
|
|
{
|
|
model: models.MultipleChoices,
|
|
as: "multipleChoices",
|
|
},
|
|
{
|
|
model: models.MatchingPairs,
|
|
as: "matchingPairs",
|
|
},
|
|
{
|
|
model: models.TrueFalse,
|
|
as: "trueFalse",
|
|
},
|
|
],
|
|
});
|
|
|
|
if (exercises.length === 0) {
|
|
return response(404, null, "No exercises found", res);
|
|
}
|
|
|
|
const result = exercises.map((exercise) => {
|
|
const exerciseData = { ...exercise.dataValues };
|
|
const questionType = exercise.QUESTION_TYPE;
|
|
|
|
if (questionType === "MCQ") {
|
|
delete exerciseData.matchingPairs;
|
|
delete exerciseData.trueFalse;
|
|
} else if (questionType === "MPQ") {
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.trueFalse;
|
|
} else if (questionType === "TFQ") {
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.matchingPairs;
|
|
} else {
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.matchingPairs;
|
|
delete exerciseData.trueFalse;
|
|
}
|
|
|
|
return exerciseData;
|
|
});
|
|
|
|
response(200, result, "Success", res);
|
|
} catch (error) {
|
|
console.log(error);
|
|
res.status(500).json({ message: "Internal Server Error" });
|
|
}
|
|
};
|
|
|
|
export const getExercisesForAdmin = async (req, res) => {
|
|
try {
|
|
const exercises = await models.Exercise.findAll({
|
|
include: [
|
|
{
|
|
model: models.MultipleChoices,
|
|
as: "multipleChoices",
|
|
attributes: ["ANSWER_KEY"],
|
|
},
|
|
{
|
|
model: models.MatchingPairs,
|
|
as: "matchingPairs",
|
|
attributes: ["LEFT_PAIR", "RIGHT_PAIR"],
|
|
},
|
|
{
|
|
model: models.TrueFalse,
|
|
as: "trueFalse",
|
|
attributes: ["IS_TRUE"],
|
|
},
|
|
],
|
|
});
|
|
|
|
const formattedExercises = exercises.map((exercise) => {
|
|
const questionType = exercise.QUESTION_TYPE;
|
|
let answerKey = null;
|
|
|
|
if (questionType === "MCQ" && exercise.multipleChoices.length > 0) {
|
|
answerKey = exercise.multipleChoices[0].ANSWER_KEY;
|
|
} else if (questionType === "MPQ" && exercise.matchingPairs.length > 0) {
|
|
answerKey = exercise.matchingPairs
|
|
.map((pair) => `${pair.LEFT_PAIR}-${pair.RIGHT_PAIR}`)
|
|
.join(", ");
|
|
} else if (questionType === "TFQ" && exercise.trueFalse.length > 0) {
|
|
answerKey = exercise.trueFalse[0].IS_TRUE === 1 ? "true" : "false";
|
|
}
|
|
|
|
return {
|
|
ID_ADMIN_EXERCISE: exercise.ID_ADMIN_EXERCISE,
|
|
ID_LEVEL: exercise.ID_LEVEL,
|
|
TITLE: exercise.TITLE,
|
|
QUESTION: exercise.QUESTION,
|
|
SCORE_WEIGHT: exercise.SCORE_WEIGHT,
|
|
QUESTION_TYPE: questionType,
|
|
AUDIO: exercise.AUDIO,
|
|
VIDEO: exercise.VIDEO,
|
|
IMAGE: exercise.IMAGE,
|
|
ANSWER_KEY: answerKey,
|
|
};
|
|
});
|
|
|
|
response(200, formattedExercises, "Success", res);
|
|
} catch (error) {
|
|
console.log(error);
|
|
response(500, null, "Error retrieving exercises data!", res);
|
|
}
|
|
};
|
|
|
|
export const getExerciseById = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
const exercise = await models.Exercise.findByPk(id, {
|
|
include: [
|
|
{
|
|
model: models.MultipleChoices,
|
|
as: "multipleChoices",
|
|
},
|
|
{
|
|
model: models.MatchingPairs,
|
|
as: "matchingPairs",
|
|
},
|
|
{
|
|
model: models.TrueFalse,
|
|
as: "trueFalse",
|
|
},
|
|
],
|
|
});
|
|
|
|
if (!exercise) {
|
|
return response(404, null, "Exercise not found", res);
|
|
}
|
|
|
|
const exerciseData = { ...exercise.dataValues };
|
|
const questionType = exercise.QUESTION_TYPE;
|
|
|
|
if (questionType === "MCQ") {
|
|
if (exerciseData.multipleChoices) {
|
|
exerciseData.multipleChoices = exerciseData.multipleChoices.map(
|
|
(choice) => {
|
|
const { ANSWER_KEY, ...rest } = choice.dataValues;
|
|
return rest;
|
|
}
|
|
);
|
|
}
|
|
delete exerciseData.matchingPairs;
|
|
delete exerciseData.trueFalse;
|
|
} else if (questionType === "MPQ") {
|
|
if (exerciseData.matchingPairs) {
|
|
exerciseData.matchingPairs = exerciseData.matchingPairs.map((pair) => {
|
|
const { LEFT_PAIR, RIGHT_PAIR, ...rest } = pair.dataValues;
|
|
return rest;
|
|
});
|
|
}
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.trueFalse;
|
|
} else if (questionType === "TFQ") {
|
|
if (exerciseData.trueFalse) {
|
|
exerciseData.trueFalse = exerciseData.trueFalse.map((tf) => {
|
|
const { IS_TRUE, ...rest } = tf.dataValues;
|
|
return rest;
|
|
});
|
|
}
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.matchingPairs;
|
|
} else {
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.matchingPairs;
|
|
delete exerciseData.trueFalse;
|
|
}
|
|
|
|
response(200, exerciseData, "Success", res);
|
|
} catch (error) {
|
|
console.log(error);
|
|
res.status(500).json({ message: "Internal Server Error" });
|
|
}
|
|
};
|
|
|
|
export const getExerciseByLevelId = async (req, res) => {
|
|
try {
|
|
const { idLevel } = req.params;
|
|
|
|
const levelExists = await models.Level.findByPk(idLevel, {
|
|
include: [
|
|
{
|
|
model: models.Topic,
|
|
as: "levelTopic",
|
|
attributes: ["NAME_TOPIC"],
|
|
},
|
|
],
|
|
attributes: ["NAME_LEVEL"],
|
|
});
|
|
|
|
if (!levelExists) {
|
|
return response(404, null, "Level not found", res);
|
|
}
|
|
|
|
const exercises = await models.Exercise.findAll({
|
|
where: { ID_LEVEL: idLevel },
|
|
include: [
|
|
{
|
|
model: models.MultipleChoices,
|
|
as: "multipleChoices",
|
|
},
|
|
{
|
|
model: models.MatchingPairs,
|
|
as: "matchingPairs",
|
|
},
|
|
{
|
|
model: models.TrueFalse,
|
|
as: "trueFalse",
|
|
},
|
|
],
|
|
});
|
|
|
|
if (!exercises || exercises.length === 0) {
|
|
return response(404, null, "No exercises found for this level", res);
|
|
}
|
|
|
|
const formattedExercises = exercises.map((exercise) => {
|
|
const exerciseData = { ...exercise.dataValues };
|
|
const questionType = exercise.QUESTION_TYPE;
|
|
|
|
if (questionType === "MCQ") {
|
|
if (exerciseData.multipleChoices) {
|
|
exerciseData.multipleChoices = exerciseData.multipleChoices.map(
|
|
(choice) => {
|
|
const { ANSWER_KEY, ...rest } = choice.dataValues;
|
|
return rest;
|
|
}
|
|
);
|
|
}
|
|
delete exerciseData.matchingPairs;
|
|
delete exerciseData.trueFalse;
|
|
} else if (questionType === "MPQ") {
|
|
if (exerciseData.matchingPairs) {
|
|
exerciseData.matchingPairs = exerciseData.matchingPairs.map(
|
|
(pair) => pair.dataValues
|
|
);
|
|
}
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.trueFalse;
|
|
} else if (questionType === "TFQ") {
|
|
if (exerciseData.trueFalse) {
|
|
exerciseData.trueFalse = exerciseData.trueFalse.map((tf) => {
|
|
const { IS_TRUE, ...rest } = tf.dataValues;
|
|
return rest;
|
|
});
|
|
}
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.matchingPairs;
|
|
} else {
|
|
delete exerciseData.multipleChoices;
|
|
delete exerciseData.matchingPairs;
|
|
delete exerciseData.trueFalse;
|
|
}
|
|
|
|
return exerciseData;
|
|
});
|
|
|
|
const responsePayload = {
|
|
NAME_TOPIC: levelExists.levelTopic.NAME_TOPIC,
|
|
NAME_LEVEL: levelExists.NAME_LEVEL,
|
|
EXERCISES: formattedExercises,
|
|
};
|
|
|
|
response(200, responsePayload, "Success", res);
|
|
} catch (error) {
|
|
console.log(error);
|
|
res.status(500).json({ message: "Internal Server Error" });
|
|
}
|
|
};
|
|
|
|
export const deleteExerciseById = async (req, res) => {
|
|
const { id } = req.params;
|
|
const transaction = await models.db.transaction();
|
|
|
|
try {
|
|
const exercise = await models.Exercise.findByPk(id, {
|
|
include: [
|
|
{
|
|
model: models.MultipleChoices,
|
|
as: "multipleChoices",
|
|
},
|
|
{
|
|
model: models.MatchingPairs,
|
|
as: "matchingPairs",
|
|
},
|
|
{
|
|
model: models.TrueFalse,
|
|
as: "trueFalse",
|
|
},
|
|
],
|
|
});
|
|
|
|
if (!exercise) {
|
|
await transaction.rollback();
|
|
return response(404, null, "Exercise not found", res);
|
|
}
|
|
|
|
await models.StdExercise.destroy({
|
|
where: { ID_ADMIN_EXERCISE: id },
|
|
transaction,
|
|
});
|
|
|
|
if (exercise.AUDIO) {
|
|
const audioPath = path.join(
|
|
"public/uploads/exercise/audio",
|
|
exercise.AUDIO
|
|
);
|
|
if (fs.existsSync(audioPath)) fs.unlinkSync(audioPath);
|
|
}
|
|
|
|
if (exercise.IMAGE) {
|
|
const imagePath = path.join(
|
|
"public/uploads/exercise/image",
|
|
exercise.IMAGE
|
|
);
|
|
if (fs.existsSync(imagePath)) fs.unlinkSync(imagePath);
|
|
}
|
|
|
|
const questionType = exercise.QUESTION_TYPE;
|
|
|
|
if (questionType === "MCQ") {
|
|
await models.MultipleChoices.destroy({
|
|
where: { ID_ADMIN_EXERCISE: id },
|
|
transaction,
|
|
});
|
|
} else if (questionType === "MPQ") {
|
|
await models.MatchingPairs.destroy({
|
|
where: { ID_ADMIN_EXERCISE: id },
|
|
transaction,
|
|
});
|
|
} else if (questionType === "TFQ") {
|
|
await models.TrueFalse.destroy({
|
|
where: { ID_ADMIN_EXERCISE: id },
|
|
transaction,
|
|
});
|
|
}
|
|
|
|
await exercise.destroy({ transaction });
|
|
|
|
await transaction.commit();
|
|
|
|
response(200, null, "Exercise and related data deleted successfully", res);
|
|
} catch (error) {
|
|
console.log(error);
|
|
await transaction.rollback();
|
|
response(500, null, "Internal Server Error", res);
|
|
}
|
|
};
|
|
|
|
export const deleteExerciseFileById = async (req, res) => {
|
|
const { id } = req.params;
|
|
const { fileType } = req.body;
|
|
|
|
if (!["audio", "image", "video"].includes(fileType)) {
|
|
return response(400, null, "Invalid file type specified", res);
|
|
}
|
|
|
|
try {
|
|
const exercise = await models.Exercise.findByPk(id);
|
|
|
|
if (!exercise) {
|
|
return response(404, null, "Exercise not found", res);
|
|
}
|
|
|
|
let filePath;
|
|
let fileName;
|
|
|
|
if (fileType === "audio" && exercise.AUDIO) {
|
|
fileName = exercise.AUDIO;
|
|
filePath = path.join("public/uploads/exercise/audio", fileName);
|
|
exercise.AUDIO = null;
|
|
} else if (fileType === "image" && exercise.IMAGE) {
|
|
fileName = exercise.IMAGE;
|
|
filePath = path.join("public/uploads/exercise/image", fileName);
|
|
exercise.IMAGE = null;
|
|
} else if (fileType === "video" && exercise.VIDEO) {
|
|
exercise.VIDEO = null;
|
|
} else {
|
|
return response(
|
|
404,
|
|
null,
|
|
`${
|
|
fileType.charAt(0).toUpperCase() + fileType.slice(1)
|
|
} file not found`,
|
|
res
|
|
);
|
|
}
|
|
|
|
if (fs.existsSync(filePath)) {
|
|
fs.unlinkSync(filePath);
|
|
}
|
|
|
|
await exercise.save();
|
|
|
|
response(
|
|
200,
|
|
exercise,
|
|
`${
|
|
fileType.charAt(0).toUpperCase() + fileType.slice(1)
|
|
} file deleted successfully`,
|
|
res
|
|
);
|
|
} catch (error) {
|
|
console.log(error);
|
|
response(500, null, "Internal Server Error", res);
|
|
}
|
|
};
|