refactor: user model function and exercises
|
|
@ -13,46 +13,44 @@ const transporter = nodemailer.createTransport({
|
|||
});
|
||||
|
||||
export const registerAdmin = async (req, res) => {
|
||||
const { name, email, password, confirmPassword } = req.body;
|
||||
const { NAME_USERS, EMAIL, PASSWORD, CONFIRM_PASSWORD } = req.body;
|
||||
|
||||
if (!name) {
|
||||
if (!NAME_USERS) {
|
||||
return response(400, null, "Name is required!", res);
|
||||
}
|
||||
|
||||
if (!email) {
|
||||
if (!EMAIL) {
|
||||
return response(400, null, "Email is required!", res);
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
if (!PASSWORD) {
|
||||
return response(400, null, "Password is required!", res);
|
||||
}
|
||||
|
||||
if (!confirmPassword) {
|
||||
if (!CONFIRM_PASSWORD) {
|
||||
return response(400, null, "Confirm Password is required!", res);
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
if (PASSWORD !== CONFIRM_PASSWORD) {
|
||||
return response(400, null, "Passwords do not match!", res);
|
||||
}
|
||||
|
||||
try {
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const hashedPassword = await bcrypt.hash(password, salt);
|
||||
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
|
||||
|
||||
const newUser = await models.User.create({
|
||||
NAME_USERS: name,
|
||||
EMAIL: email,
|
||||
NAME_USERS: NAME_USERS,
|
||||
EMAIL: EMAIL,
|
||||
PASSWORD: hashedPassword,
|
||||
ROLE: "admin",
|
||||
PICTURE: "default-avatar.jpeg",
|
||||
});
|
||||
|
||||
const adminResponse = {
|
||||
id: newUser.ID,
|
||||
name: newUser.NAME_USERS,
|
||||
email: newUser.EMAIL,
|
||||
role: newUser.ROLE,
|
||||
picture: newUser.PICTURE,
|
||||
ID: newUser.ID,
|
||||
NAME_USERS: newUser.NAME_USERS,
|
||||
EMAIL: newUser.EMAIL,
|
||||
ROLE: newUser.ROLE,
|
||||
};
|
||||
|
||||
response(200, adminResponse, "Admin registration successful", res);
|
||||
|
|
@ -68,29 +66,29 @@ export const registerAdmin = async (req, res) => {
|
|||
};
|
||||
|
||||
export const registerTeacher = async (req, res) => {
|
||||
const { name, email, nip, password, confirmPassword } = req.body;
|
||||
const { NAME_USERS, EMAIL, NIP, PASSWORD, CONFIRM_PASSWORD } = req.body;
|
||||
|
||||
if (!name) {
|
||||
if (!NAME_USERS) {
|
||||
return response(400, null, "Name is required!", res);
|
||||
}
|
||||
|
||||
if (!email) {
|
||||
if (!EMAIL) {
|
||||
return response(400, null, "Email is required!", res);
|
||||
}
|
||||
|
||||
if (!nip) {
|
||||
if (!NIP) {
|
||||
return response(400, null, "NIP is required for teachers!", res);
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
if (!PASSWORD) {
|
||||
return response(400, null, "Password is required!", res);
|
||||
}
|
||||
|
||||
if (!confirmPassword) {
|
||||
if (!CONFIRM_PASSWORD) {
|
||||
return response(400, null, "Confirm Password is required!", res);
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
if (PASSWORD !== CONFIRM_PASSWORD) {
|
||||
return response(400, null, "Passwords do not match!", res);
|
||||
}
|
||||
|
||||
|
|
@ -98,15 +96,14 @@ export const registerTeacher = async (req, res) => {
|
|||
|
||||
try {
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const hashedPassword = await bcrypt.hash(password, salt);
|
||||
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
|
||||
|
||||
const newUser = await models.User.create(
|
||||
{
|
||||
NAME_USERS: name,
|
||||
EMAIL: email,
|
||||
NAME_USERS: NAME_USERS,
|
||||
EMAIL: EMAIL,
|
||||
PASSWORD: hashedPassword,
|
||||
ROLE: "teacher",
|
||||
PICTURE: "default-avatar.jpeg",
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
|
|
@ -114,7 +111,7 @@ export const registerTeacher = async (req, res) => {
|
|||
await models.Teacher.create(
|
||||
{
|
||||
ID: newUser.ID,
|
||||
NIP: nip,
|
||||
NIP: NIP,
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
|
|
@ -122,12 +119,11 @@ export const registerTeacher = async (req, res) => {
|
|||
await transaction.commit();
|
||||
|
||||
const teacherResponse = {
|
||||
id: newUser.ID,
|
||||
name: newUser.NAME_USERS,
|
||||
email: newUser.EMAIL,
|
||||
nip: nip,
|
||||
role: newUser.ROLE,
|
||||
picture: newUser.PICTURE,
|
||||
ID: newUser.ID,
|
||||
NAME_USERS: newUser.NAME_USERS,
|
||||
EMAIL: newUser.EMAIL,
|
||||
NIP: NIP,
|
||||
ROLE: newUser.ROLE,
|
||||
};
|
||||
|
||||
response(200, teacherResponse, "Teacher registration successful", res);
|
||||
|
|
@ -152,29 +148,29 @@ export const registerTeacher = async (req, res) => {
|
|||
};
|
||||
|
||||
export const registerStudent = async (req, res) => {
|
||||
const { name, email, nisn, password, confirmPassword } = req.body;
|
||||
const { NAME_USERS, EMAIL, NISN, PASSWORD, CONFIRM_PASSWORD } = req.body;
|
||||
|
||||
if (!name) {
|
||||
if (!NAME_USERS) {
|
||||
return response(400, null, "Name is required!", res);
|
||||
}
|
||||
|
||||
if (!email) {
|
||||
if (!EMAIL) {
|
||||
return response(400, null, "Email is required!", res);
|
||||
}
|
||||
|
||||
if (!nisn) {
|
||||
if (!NISN) {
|
||||
return response(400, null, "NISN is required for students!", res);
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
if (!PASSWORD) {
|
||||
return response(400, null, "Password is required!", res);
|
||||
}
|
||||
|
||||
if (!confirmPassword) {
|
||||
if (!CONFIRM_PASSWORD) {
|
||||
return response(400, null, "Confirm Password is required!", res);
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
if (PASSWORD !== CONFIRM_PASSWORD) {
|
||||
return response(400, null, "Passwords do not match!", res);
|
||||
}
|
||||
|
||||
|
|
@ -182,15 +178,14 @@ export const registerStudent = async (req, res) => {
|
|||
|
||||
try {
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const hashedPassword = await bcrypt.hash(password, salt);
|
||||
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
|
||||
|
||||
const newUser = await models.User.create(
|
||||
{
|
||||
NAME_USERS: name,
|
||||
EMAIL: email,
|
||||
NAME_USERS: NAME_USERS,
|
||||
EMAIL: EMAIL,
|
||||
PASSWORD: hashedPassword,
|
||||
ROLE: "student",
|
||||
PICTURE: "default-avatar.jpeg",
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
|
|
@ -198,7 +193,7 @@ export const registerStudent = async (req, res) => {
|
|||
await models.Student.create(
|
||||
{
|
||||
ID: newUser.ID,
|
||||
NISN: nisn,
|
||||
NISN: NISN,
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
|
|
@ -206,12 +201,11 @@ export const registerStudent = async (req, res) => {
|
|||
await transaction.commit();
|
||||
|
||||
const studentResponse = {
|
||||
id: newUser.ID,
|
||||
name: newUser.NAME_USERS,
|
||||
email: newUser.EMAIL,
|
||||
nisn: nisn,
|
||||
role: newUser.ROLE,
|
||||
picture: newUser.PICTURE,
|
||||
ID: newUser.ID,
|
||||
NAME_USERS: newUser.NAME_USERS,
|
||||
EMAIL: newUser.EMAIL,
|
||||
NISN: NISN,
|
||||
ROLE: newUser.ROLE,
|
||||
};
|
||||
|
||||
response(200, studentResponse, "Student registration successful", res);
|
||||
|
|
@ -236,40 +230,42 @@ export const registerStudent = async (req, res) => {
|
|||
};
|
||||
|
||||
export const loginUser = async (req, res) => {
|
||||
const { email, password } = req.body;
|
||||
const { EMAIL, PASSWORD } = req.body;
|
||||
|
||||
if (!email) {
|
||||
if (!EMAIL) {
|
||||
return response(400, null, "Email is required!", res);
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
if (!PASSWORD) {
|
||||
return response(400, null, "Password is required!", res);
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await models.User.findOne({ where: { email } });
|
||||
const user = await models.User.findOne({ where: { EMAIL } });
|
||||
|
||||
if (!user) {
|
||||
return response(404, null, "User data not found!", res);
|
||||
}
|
||||
|
||||
const validPassword = await bcrypt.compare(password, user.PASSWORD);
|
||||
const validPassword = await bcrypt.compare(PASSWORD, user.PASSWORD);
|
||||
if (!validPassword) {
|
||||
return response(401, null, "The password you entered is incorrect!", res);
|
||||
}
|
||||
|
||||
const accessToken = jwt.sign(
|
||||
{ id: user.ID },
|
||||
{ ID: user.ID,
|
||||
ROLE: user.ROLE
|
||||
},
|
||||
process.env.ACCESS_TOKEN_SECRET,
|
||||
{ expiresIn: "6h" }
|
||||
);
|
||||
|
||||
const userResponse = {
|
||||
id: user.ID,
|
||||
name: user.NAME_USERS,
|
||||
email: user.EMAIL,
|
||||
roles: user.ROLE,
|
||||
token: `Bearer ${accessToken}`,
|
||||
ID: user.ID,
|
||||
NAME_USERS: user.NAME_USERS,
|
||||
EMAIL: user.EMAIL,
|
||||
ROLE: user.ROLE,
|
||||
TOKEN: `Bearer ${accessToken}`,
|
||||
};
|
||||
|
||||
response(200, userResponse, "Login successful", res);
|
||||
|
|
@ -284,14 +280,14 @@ export const logoutUser = (req, res) => {
|
|||
};
|
||||
|
||||
export const forgotPassword = async (req, res) => {
|
||||
const { email } = req.body;
|
||||
const { EMAIL } = req.body;
|
||||
|
||||
if (!email) {
|
||||
if (!EMAIL) {
|
||||
return response(400, null, "Email is required!", res);
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await models.User.findOne({ where: { EMAIL: email } });
|
||||
const user = await models.User.findOne({ where: { EMAIL: EMAIL } });
|
||||
|
||||
if (!user) {
|
||||
return response(404, null, "Email is not registered!", res);
|
||||
|
|
@ -327,26 +323,26 @@ export const forgotPassword = async (req, res) => {
|
|||
};
|
||||
|
||||
export const resetPassword = async (req, res) => {
|
||||
const { token, newPassword, confirmNewPassword } = req.body;
|
||||
const { TOKEN, NEW_PASSWORD, CONFIRM_NEW_PASSWORD } = req.body;
|
||||
|
||||
if (!token) {
|
||||
if (!TOKEN) {
|
||||
return response(400, null, "Token is required!", res);
|
||||
}
|
||||
|
||||
if (!newPassword) {
|
||||
if (!NEW_PASSWORD) {
|
||||
return response(400, null, "New password is required!", res);
|
||||
}
|
||||
|
||||
if (!confirmNewPassword) {
|
||||
if (!CONFIRM_NEW_PASSWORD) {
|
||||
return response(400, null, "Confirm new password is required!", res);
|
||||
}
|
||||
|
||||
if (newPassword !== confirmNewPassword) {
|
||||
if (NEW_PASSWORD !== CONFIRM_NEW_PASSWORD) {
|
||||
return response(400, null, "Passwords do not match!", res);
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.RESET_PASSWORD_SECRET);
|
||||
const decoded = jwt.verify(TOKEN, process.env.RESET_PASSWORD_SECRET);
|
||||
const user = await models.User.findOne({ where: { ID: decoded.id } });
|
||||
|
||||
if (!user) {
|
||||
|
|
@ -354,7 +350,7 @@ export const resetPassword = async (req, res) => {
|
|||
}
|
||||
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const hashedPassword = await bcrypt.hash(newPassword, salt);
|
||||
const hashedPassword = await bcrypt.hash(NEW_PASSWORD, salt);
|
||||
|
||||
user.PASSWORD = hashedPassword;
|
||||
await user.save();
|
||||
|
|
|
|||
|
|
@ -83,17 +83,11 @@ export const getExercisesForAdmin = async (req, res) => {
|
|||
|
||||
if (questionType === "MCQ" && exercise.multipleChoices.length > 0) {
|
||||
answerKey = exercise.multipleChoices[0].ANSWER_KEY;
|
||||
} else if (
|
||||
questionType === "MPQ" &&
|
||||
exercise.matchingPairs.length > 0
|
||||
) {
|
||||
} 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
|
||||
) {
|
||||
} else if (questionType === "TFQ" && exercise.trueFalse.length > 0) {
|
||||
answerKey = exercise.trueFalse[0].IS_TRUE === 1 ? "true" : "false";
|
||||
}
|
||||
|
||||
|
|
@ -168,6 +162,141 @@ export const getExerciseById = async (req, res) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const getExerciseByLevelId = async (req, res) => {
|
||||
try {
|
||||
const { idLevel } = req.params;
|
||||
|
||||
const levelExists = await models.Level.findByPk(idLevel);
|
||||
|
||||
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") {
|
||||
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, formattedExercises, "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);
|
||||
// }
|
||||
|
||||
// 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 deleteExerciseById = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const transaction = await models.db.transaction();
|
||||
|
|
@ -195,13 +324,10 @@ export const deleteExerciseById = async (req, res) => {
|
|||
return response(404, null, "Exercise not found", res);
|
||||
}
|
||||
|
||||
if (exercise.VIDEO) {
|
||||
const videoPath = path.join(
|
||||
"public/uploads/exercise/video",
|
||||
exercise.VIDEO
|
||||
);
|
||||
if (fs.existsSync(videoPath)) fs.unlinkSync(videoPath);
|
||||
}
|
||||
await models.StdExercise.destroy({
|
||||
where: { ID_ADMIN_EXERCISE: id },
|
||||
transaction,
|
||||
});
|
||||
|
||||
if (exercise.AUDIO) {
|
||||
const audioPath = path.join(
|
||||
|
|
@ -254,7 +380,7 @@ export const deleteExerciseFileById = async (req, res) => {
|
|||
const { id } = req.params;
|
||||
const { fileType } = req.body;
|
||||
|
||||
if (!["audio", "video", "image"].includes(fileType)) {
|
||||
if (!["audio", "image", "video"].includes(fileType)) {
|
||||
return response(400, null, "Invalid file type specified", res);
|
||||
}
|
||||
|
||||
|
|
@ -268,11 +394,7 @@ export const deleteExerciseFileById = async (req, res) => {
|
|||
let filePath;
|
||||
let fileName;
|
||||
|
||||
if (fileType === "video" && exercise.VIDEO) {
|
||||
fileName = exercise.VIDEO;
|
||||
filePath = path.join("public/uploads/exercise/video", fileName);
|
||||
exercise.VIDEO = null;
|
||||
} else if (fileType === "audio" && exercise.AUDIO) {
|
||||
if (fileType === "audio" && exercise.AUDIO) {
|
||||
fileName = exercise.AUDIO;
|
||||
filePath = path.join("public/uploads/exercise/audio", fileName);
|
||||
exercise.AUDIO = null;
|
||||
|
|
@ -280,6 +402,8 @@ export const deleteExerciseFileById = async (req, res) => {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export const getLevels = async (req, res) => {
|
|||
response(200, levels, "Success", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(500).json({ message: "Internal Server Error" });
|
||||
response(500, null, "Error retrieving levels data!", res);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -54,6 +54,74 @@ export const getLevelById = async (req, res) => {
|
|||
}
|
||||
|
||||
response(200, level, "Success", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const getLevelsByTopicId = async (req, res) => {
|
||||
try {
|
||||
const { idTopic } = req.params;
|
||||
const { ID } = req.user;
|
||||
|
||||
const topicExists = await models.Topic.findByPk(idTopic);
|
||||
if (!topicExists) {
|
||||
return response(404, null, "Topic not found", res);
|
||||
}
|
||||
|
||||
const levels = await models.Level.findAll({
|
||||
where: {
|
||||
ID_TOPIC: idTopic,
|
||||
},
|
||||
attributes: {
|
||||
exclude: [
|
||||
"ROUTE_1",
|
||||
"ROUTE_2",
|
||||
"ROUTE_3",
|
||||
"ROUTE_4",
|
||||
"ROUTE_5",
|
||||
"ROUTE_6",
|
||||
],
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: models.StdLearning,
|
||||
as: "stdLearning",
|
||||
attributes: ["SCORE", "ID_STUDENT_LEARNING"],
|
||||
where: {
|
||||
ID: ID,
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!levels || levels.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ message: "No levels found for the given topic." });
|
||||
}
|
||||
|
||||
const levelsWithScore = levels.map((level) => {
|
||||
const SCORE =
|
||||
level.stdLearning.length > 0 ? level.stdLearning[0].SCORE : 0;
|
||||
const ID_STUDENT_LEARNING =
|
||||
level.stdLearning.length > 0
|
||||
? level.stdLearning[0].ID_STUDENT_LEARNING
|
||||
: null;
|
||||
|
||||
const levelJSON = level.toJSON();
|
||||
delete levelJSON.stdLearning;
|
||||
|
||||
return {
|
||||
...levelJSON,
|
||||
ID_STUDENT_LEARNING,
|
||||
SCORE,
|
||||
};
|
||||
});
|
||||
|
||||
res.status(200).json({ message: "Success", data: levelsWithScore });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(500).json({ message: "Internal Server Error" });
|
||||
|
|
@ -61,21 +129,21 @@ export const getLevelById = async (req, res) => {
|
|||
};
|
||||
|
||||
export const createLevel = async (req, res, next) => {
|
||||
const { NAME_LEVEL, ID_SECTION, ID_TOPIC, CONTENT } = req.body;
|
||||
const { video, image, audio } = req.filesToSave || {};
|
||||
const { NAME_LEVEL, ID_SECTION, ID_TOPIC, CONTENT, VIDEO } = req.body;
|
||||
const { AUDIO, IMAGE } = req.filesToSave || {};
|
||||
|
||||
if (!NAME_LEVEL) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(400, null, "Level name is required", res);
|
||||
}
|
||||
|
||||
if (!ID_SECTION) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(400, null, "Section is required", res);
|
||||
}
|
||||
|
||||
if (!ID_TOPIC) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(400, null, "Topic is required", res);
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +153,7 @@ export const createLevel = async (req, res, next) => {
|
|||
});
|
||||
|
||||
if (!sectionWithTopic) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(
|
||||
400,
|
||||
null,
|
||||
|
|
@ -99,7 +167,7 @@ export const createLevel = async (req, res, next) => {
|
|||
});
|
||||
|
||||
if (existingLevel) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(
|
||||
409,
|
||||
null,
|
||||
|
|
@ -114,7 +182,7 @@ export const createLevel = async (req, res, next) => {
|
|||
ID_TOPIC,
|
||||
IS_PRETEST: req.body.IS_PRETEST || 0,
|
||||
CONTENT,
|
||||
VIDEO: null,
|
||||
VIDEO: VIDEO || null,
|
||||
AUDIO: null,
|
||||
IMAGE: null,
|
||||
ROUTE_1: req.body.ROUTE_1,
|
||||
|
|
@ -127,17 +195,13 @@ export const createLevel = async (req, res, next) => {
|
|||
|
||||
req.body.newLevelId = newLevel.ID_LEVEL;
|
||||
|
||||
const videoFilename = video
|
||||
? saveFileToDisk(video, "video", ID_TOPIC, ID_SECTION, newLevel.ID_LEVEL)
|
||||
const audioFilename = AUDIO
|
||||
? saveFileToDisk(AUDIO, "AUDIO", ID_TOPIC, ID_SECTION, newLevel.ID_LEVEL)
|
||||
: null;
|
||||
const audioFilename = audio
|
||||
? saveFileToDisk(audio, "audio", ID_TOPIC, ID_SECTION, newLevel.ID_LEVEL)
|
||||
: null;
|
||||
const imageFilename = image
|
||||
? saveFileToDisk(image, "image", ID_TOPIC, ID_SECTION, newLevel.ID_LEVEL)
|
||||
const imageFilename = IMAGE
|
||||
? saveFileToDisk(IMAGE, "IMAGE", ID_TOPIC, ID_SECTION, newLevel.ID_LEVEL)
|
||||
: null;
|
||||
|
||||
newLevel.VIDEO = videoFilename;
|
||||
newLevel.AUDIO = audioFilename;
|
||||
newLevel.IMAGE = imageFilename;
|
||||
await newLevel.save();
|
||||
|
|
@ -147,22 +211,22 @@ export const createLevel = async (req, res, next) => {
|
|||
response(201, newLevel, "Level created successfully", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const updateLevelById = async (req, res, next) => {
|
||||
const { id } = req.params;
|
||||
const { NAME_LEVEL, ID_SECTION, ID_TOPIC, CONTENT } = req.body;
|
||||
const { NAME_LEVEL, ID_SECTION, ID_TOPIC, CONTENT, VIDEO } = req.body;
|
||||
|
||||
const { video, image, audio } = req.filesToSave || {};
|
||||
const { AUDIO, IMAGE } = req.filesToSave || {};
|
||||
|
||||
try {
|
||||
const level = await models.Level.findByPk(id);
|
||||
|
||||
if (!level) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +235,7 @@ export const updateLevelById = async (req, res, next) => {
|
|||
});
|
||||
|
||||
if (!sectionWithTopic) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(
|
||||
400,
|
||||
null,
|
||||
|
|
@ -190,7 +254,7 @@ export const updateLevelById = async (req, res, next) => {
|
|||
});
|
||||
|
||||
if (existingLevel) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(
|
||||
409,
|
||||
null,
|
||||
|
|
@ -212,26 +276,11 @@ export const updateLevelById = async (req, res, next) => {
|
|||
if (ID_TOPIC) level.ID_TOPIC = ID_TOPIC;
|
||||
if (CONTENT) level.CONTENT = CONTENT;
|
||||
|
||||
if (video) {
|
||||
if (level.VIDEO) {
|
||||
const oldVideoPath = path.join(
|
||||
"public/uploads/level/video",
|
||||
level.VIDEO
|
||||
);
|
||||
if (fs.existsSync(oldVideoPath)) {
|
||||
fs.unlinkSync(oldVideoPath);
|
||||
}
|
||||
}
|
||||
level.VIDEO = saveFileToDisk(
|
||||
video,
|
||||
"video",
|
||||
ID_TOPIC || level.ID_TOPIC,
|
||||
ID_SECTION || level.ID_SECTION,
|
||||
level.ID_LEVEL
|
||||
);
|
||||
if (VIDEO) {
|
||||
level.VIDEO = VIDEO;
|
||||
}
|
||||
|
||||
if (audio) {
|
||||
if (AUDIO) {
|
||||
if (level.AUDIO) {
|
||||
const oldAudioPath = path.join(
|
||||
"public/uploads/level/audio",
|
||||
|
|
@ -242,15 +291,15 @@ export const updateLevelById = async (req, res, next) => {
|
|||
}
|
||||
}
|
||||
level.AUDIO = saveFileToDisk(
|
||||
audio,
|
||||
"audio",
|
||||
AUDIO,
|
||||
"AUDIO",
|
||||
ID_TOPIC || level.ID_TOPIC,
|
||||
ID_SECTION || level.ID_SECTION,
|
||||
level.ID_LEVEL
|
||||
);
|
||||
}
|
||||
|
||||
if (image) {
|
||||
if (IMAGE) {
|
||||
if (level.IMAGE) {
|
||||
const oldImagePath = path.join(
|
||||
"public/uploads/level/image",
|
||||
|
|
@ -261,8 +310,8 @@ export const updateLevelById = async (req, res, next) => {
|
|||
}
|
||||
}
|
||||
level.IMAGE = saveFileToDisk(
|
||||
image,
|
||||
"image",
|
||||
IMAGE,
|
||||
"IMAGE",
|
||||
ID_TOPIC || level.ID_TOPIC,
|
||||
ID_SECTION || level.ID_SECTION,
|
||||
level.ID_LEVEL
|
||||
|
|
@ -278,7 +327,7 @@ export const updateLevelById = async (req, res, next) => {
|
|||
response(200, level, "Level updated successfully", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
|
@ -299,11 +348,6 @@ export const deleteLevelById = async (req, res, next) => {
|
|||
}
|
||||
};
|
||||
|
||||
if (level.VIDEO) {
|
||||
const videoPath = path.join("public/uploads/level/video", level.VIDEO);
|
||||
deleteFile(videoPath);
|
||||
}
|
||||
|
||||
if (level.AUDIO) {
|
||||
const audioPath = path.join("public/uploads/level/audio", level.AUDIO);
|
||||
deleteFile(audioPath);
|
||||
|
|
@ -327,6 +371,132 @@ export const deleteLevelById = async (req, res, next) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const unlockPreviousRoutes = async (req, res) => {
|
||||
const { NEXT_LEARNING } = req.params;
|
||||
export const getPreviousLevel = async (req, res) => {
|
||||
try {
|
||||
const { next_learning } = req.params;
|
||||
const { ID } = req.user;
|
||||
|
||||
const currentLevel = await models.Level.findByPk(next_learning, {
|
||||
include: [
|
||||
{
|
||||
model: models.StdLearning,
|
||||
as: "stdLearning",
|
||||
attributes: ["SCORE", "ID_STUDENT_LEARNING"],
|
||||
where: {
|
||||
ID: ID,
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
attributes: {
|
||||
exclude: [
|
||||
"ROUTE_1",
|
||||
"ROUTE_2",
|
||||
"ROUTE_3",
|
||||
"ROUTE_4",
|
||||
"ROUTE_5",
|
||||
"ROUTE_6",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
if (!currentLevel) {
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
||||
const { NAME_LEVEL, ID_TOPIC } = currentLevel;
|
||||
const levelNumber = parseInt(NAME_LEVEL.replace("Level ", ""));
|
||||
|
||||
if (isNaN(levelNumber)) {
|
||||
return response(400, null, "Invalid level format", res);
|
||||
}
|
||||
|
||||
const previousLevels = await models.Level.findAll({
|
||||
where: {
|
||||
ID_TOPIC: ID_TOPIC,
|
||||
NAME_LEVEL: {
|
||||
[models.Op.or]: [
|
||||
{ [models.Op.like]: "Pretest" },
|
||||
{ [models.Op.regexp]: `^Level [0-9]+$` },
|
||||
],
|
||||
},
|
||||
[models.Op.or]: [
|
||||
{ IS_PRETEST: 1 },
|
||||
{
|
||||
NAME_LEVEL: {
|
||||
[models.Op.lt]: `Level ${levelNumber}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
order: [["NAME_LEVEL", "ASC"]],
|
||||
attributes: {
|
||||
exclude: [
|
||||
"ROUTE_1",
|
||||
"ROUTE_2",
|
||||
"ROUTE_3",
|
||||
"ROUTE_4",
|
||||
"ROUTE_5",
|
||||
"ROUTE_6",
|
||||
],
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: models.StdLearning,
|
||||
as: "stdLearning",
|
||||
attributes: ["SCORE", "ID_STUDENT_LEARNING"],
|
||||
where: {
|
||||
ID: ID,
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const previousLevelsWithScore = previousLevels.map((level) => {
|
||||
const SCORE =
|
||||
level.stdLearning.length > 0 ? level.stdLearning[0].SCORE : 0;
|
||||
const ID_STUDENT_LEARNING =
|
||||
level.stdLearning.length > 0
|
||||
? level.stdLearning[0].ID_STUDENT_LEARNING
|
||||
: null;
|
||||
|
||||
const levelJSON = level.toJSON();
|
||||
delete levelJSON.stdLearning;
|
||||
|
||||
return {
|
||||
...levelJSON,
|
||||
ID_STUDENT_LEARNING,
|
||||
SCORE,
|
||||
};
|
||||
});
|
||||
|
||||
const currentLevelWithScore = {
|
||||
...currentLevel.toJSON(),
|
||||
ID_STUDENT_LEARNING:
|
||||
currentLevel.stdLearning.length > 0
|
||||
? currentLevel.stdLearning[0].ID_STUDENT_LEARNING
|
||||
: null,
|
||||
SCORE:
|
||||
currentLevel.stdLearning.length > 0
|
||||
? currentLevel.stdLearning[0].SCORE
|
||||
: 0,
|
||||
};
|
||||
|
||||
delete currentLevelWithScore.stdLearning;
|
||||
|
||||
if (!previousLevelsWithScore.length && !currentLevelWithScore) {
|
||||
return response(404, null, "No levels found", res);
|
||||
}
|
||||
|
||||
const result = {
|
||||
currentLevel: currentLevelWithScore,
|
||||
previousLevels: previousLevelsWithScore,
|
||||
};
|
||||
|
||||
response(200, result, "Success", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(500).json({ message: "Internal Server Error" });
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,15 +36,15 @@ export const getSectionById = async (req, res) => {
|
|||
export const createSection = async (req, res) => {
|
||||
const { NAME_SECTION, DESCRIPTION_SECTION } = req.body;
|
||||
|
||||
const { thumbnail } = req.filesToSave || {};
|
||||
const { THUMBNAIL } = req.filesToSave || {};
|
||||
|
||||
if (!NAME_SECTION) {
|
||||
clearFileBuffers({ thumbnail });
|
||||
clearFileBuffers({ THUMBNAIL });
|
||||
return response(400, null, "Section name is required", res);
|
||||
}
|
||||
|
||||
if (!DESCRIPTION_SECTION) {
|
||||
clearFileBuffers({ thumbnail });
|
||||
clearFileBuffers({ THUMBNAIL });
|
||||
return response(400, null, "Description is required", res);
|
||||
}
|
||||
|
||||
|
|
@ -55,8 +55,8 @@ export const createSection = async (req, res) => {
|
|||
THUMBNAIL: null,
|
||||
});
|
||||
|
||||
const thumbnailFilename = thumbnail
|
||||
? saveFileToDisk(thumbnail, "thumbnail", newSection.ID_SECTION)
|
||||
const thumbnailFilename = THUMBNAIL
|
||||
? saveFileToDisk(THUMBNAIL, "THUMBNAIL", newSection.ID_SECTION)
|
||||
: null;
|
||||
|
||||
newSection.THUMBNAIL = thumbnailFilename;
|
||||
|
|
@ -65,7 +65,7 @@ export const createSection = async (req, res) => {
|
|||
response(201, newSection, "Section created successfully", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
clearFileBuffers({ thumbnail });
|
||||
clearFileBuffers({ THUMBNAIL });
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
|
@ -74,20 +74,20 @@ export const updateSectionById = async (req, res) => {
|
|||
const { id } = req.params;
|
||||
const { NAME_SECTION, DESCRIPTION_SECTION } = req.body;
|
||||
|
||||
const { thumbnail } = req.filesToSave || {};
|
||||
const { THUMBNAIL } = req.filesToSave || {};
|
||||
|
||||
try {
|
||||
const section = await models.Section.findByPk(id);
|
||||
|
||||
if (!section) {
|
||||
clearFileBuffers({ thumbnail });
|
||||
clearFileBuffers({ THUMBNAIL });
|
||||
return response(404, null, "Section not found", res);
|
||||
}
|
||||
|
||||
if (NAME_SECTION) section.NAME_SECTION = NAME_SECTION;
|
||||
if (DESCRIPTION_SECTION) section.DESCRIPTION_SECTION = DESCRIPTION_SECTION;
|
||||
|
||||
if (thumbnail) {
|
||||
if (THUMBNAIL) {
|
||||
if (section.THUMBNAIL) {
|
||||
const oldThumbnailPath = path.join(
|
||||
"public/uploads/section",
|
||||
|
|
@ -98,8 +98,8 @@ export const updateSectionById = async (req, res) => {
|
|||
}
|
||||
}
|
||||
section.THUMBNAIL = saveFileToDisk(
|
||||
thumbnail,
|
||||
"thumbnail",
|
||||
THUMBNAIL,
|
||||
"THUMBNAIL",
|
||||
section.ID_SECTION
|
||||
);
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ export const updateSectionById = async (req, res) => {
|
|||
response(200, section, "Section updated successfully", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
clearFileBuffers({ thumbnail });
|
||||
clearFileBuffers({ THUMBNAIL });
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,8 +27,32 @@ export const getTopicById = async (req, res) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const getTopicBySectionId = async (req, res) => {
|
||||
try {
|
||||
const { sectionId } = req.params;
|
||||
|
||||
const sectionExists = await models.Section.findByPk(sectionId);
|
||||
if (!sectionExists) {
|
||||
return response(404, null, "Section not found", res);
|
||||
}
|
||||
|
||||
const topics = await models.Topic.findAll({
|
||||
where: { ID_SECTION: sectionId },
|
||||
});
|
||||
|
||||
if (!topics || topics.length === 0) {
|
||||
return response(404, null, "No topics found for this section", res);
|
||||
}
|
||||
|
||||
response(200, topics, "Success", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const createTopic = async (req, res) => {
|
||||
const { ID_SECTION, NAME_TOPIC, DESCRIPTION_TOPIC } = req.body;
|
||||
const { ID_SECTION, NAME_TOPIC, DESCRIPTION_TOPIC, OBJECTIVES } = req.body;
|
||||
|
||||
if (!ID_SECTION) {
|
||||
return response(400, null, "Section ID is required", res);
|
||||
|
|
@ -39,7 +63,11 @@ export const createTopic = async (req, res) => {
|
|||
}
|
||||
|
||||
if (!DESCRIPTION_TOPIC) {
|
||||
return response(400, null, "Topic Description is required", res);
|
||||
return response(400, null, "Topic description is required", res);
|
||||
}
|
||||
|
||||
if (!OBJECTIVES) {
|
||||
return response(400, null, "Topic objectives are required", res);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -52,6 +80,7 @@ export const createTopic = async (req, res) => {
|
|||
ID_SECTION,
|
||||
NAME_TOPIC,
|
||||
DESCRIPTION_TOPIC,
|
||||
OBJECTIVES,
|
||||
});
|
||||
|
||||
response(201, newTopic, "Topic created successfully", res);
|
||||
|
|
@ -63,7 +92,7 @@ export const createTopic = async (req, res) => {
|
|||
|
||||
export const updateTopicById = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { ID_SECTION, NAME_TOPIC, DESCRIPTION_TOPIC } = req.body;
|
||||
const { ID_SECTION, NAME_TOPIC, DESCRIPTION_TOPIC, OBJECTIVES } = req.body;
|
||||
|
||||
try {
|
||||
const topic = await models.Topic.findByPk(id);
|
||||
|
|
@ -88,6 +117,10 @@ export const updateTopicById = async (req, res) => {
|
|||
topic.DESCRIPTION_TOPIC = DESCRIPTION_TOPIC;
|
||||
}
|
||||
|
||||
if (OBJECTIVES) {
|
||||
topic.OBJECTIVES = OBJECTIVES;
|
||||
}
|
||||
|
||||
await topic.save();
|
||||
|
||||
response(200, topic, "Topic updated successfully", res);
|
||||
|
|
@ -115,3 +148,75 @@ export const deleteTopicById = async (req, res) => {
|
|||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const getCompletedTopics = async (req, res) => {
|
||||
try {
|
||||
const user = req.user;
|
||||
const userId = user.ID;
|
||||
|
||||
const completedLevels = await models.StdLearning.findAll({
|
||||
where: {
|
||||
ID: userId,
|
||||
IS_PASS: 1,
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: models.Level,
|
||||
as: "level",
|
||||
include: [
|
||||
{
|
||||
model: models.Topic,
|
||||
as: "levelTopic",
|
||||
attributes: [
|
||||
"ID_TOPIC",
|
||||
"NAME_TOPIC",
|
||||
"DESCRIPTION_TOPIC",
|
||||
"OBJECTIVES",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!completedLevels.length) {
|
||||
return response(404, null, "No completed topics found", res);
|
||||
}
|
||||
|
||||
const completedTopics = [];
|
||||
for (const levelRecord of completedLevels) {
|
||||
const level = levelRecord.level;
|
||||
|
||||
const level6 = await models.Level.findOne({
|
||||
where: {
|
||||
NAME_LEVEL: "Level 6",
|
||||
ID_TOPIC: level.ID_TOPIC,
|
||||
},
|
||||
});
|
||||
|
||||
if (level6 && level.ID_LEVEL === level6.ID_LEVEL) {
|
||||
const topic = level.levelTopic;
|
||||
completedTopics.push({
|
||||
ID_TOPIC: topic.ID_TOPIC,
|
||||
NAME_TOPIC: topic.NAME_TOPIC,
|
||||
DESCRIPTION_TOPIC: topic.DESCRIPTION_TOPIC,
|
||||
OBJECTIVES: topic.OBJECTIVES,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!completedTopics.length) {
|
||||
return response(404, null, "No completed topics for Level 6 found", res);
|
||||
}
|
||||
|
||||
response(
|
||||
200,
|
||||
completedTopics,
|
||||
"Completed topics fetched successfully",
|
||||
res
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import fs from "fs";
|
|||
import path from "path";
|
||||
|
||||
export const createMatchingPairsExercise = async (req, res) => {
|
||||
const { ID_LEVEL, TITLE, QUESTION, SCORE_WEIGHT } = req.body;
|
||||
const { ID_LEVEL, TITLE, QUESTION, SCORE_WEIGHT, VIDEO } = req.body;
|
||||
let PAIRS = req.body.PAIRS;
|
||||
|
||||
try {
|
||||
|
|
@ -19,7 +19,7 @@ export const createMatchingPairsExercise = async (req, res) => {
|
|||
return response(400, null, "Invalid PAIRS format", res);
|
||||
}
|
||||
|
||||
const { video, image, audio } = req.filesToSave || {};
|
||||
const { IMAGE, AUDIO } = req.filesToSave || {};
|
||||
|
||||
if (!ID_LEVEL) return response(400, null, "Level ID is required", res);
|
||||
if (!QUESTION) return response(400, null, "Question is required", res);
|
||||
|
|
@ -33,7 +33,7 @@ export const createMatchingPairsExercise = async (req, res) => {
|
|||
try {
|
||||
const level = await models.Level.findByPk(ID_LEVEL);
|
||||
if (!level) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ export const createMatchingPairsExercise = async (req, res) => {
|
|||
where: { ID_LEVEL, TITLE: generatedTitle },
|
||||
});
|
||||
if (existingExercise) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
return response(
|
||||
400,
|
||||
null,
|
||||
|
|
@ -66,23 +66,19 @@ export const createMatchingPairsExercise = async (req, res) => {
|
|||
SCORE_WEIGHT,
|
||||
QUESTION_TYPE: "MPQ",
|
||||
AUDIO: null,
|
||||
VIDEO: null,
|
||||
VIDEO: VIDEO || null,
|
||||
IMAGE: null,
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
|
||||
const videoFilename = video
|
||||
? saveFileToDisk(video, "video", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
const audioFilename = AUDIO
|
||||
? saveFileToDisk(AUDIO, "AUDIO", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
const audioFilename = audio
|
||||
? saveFileToDisk(audio, "audio", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
const imageFilename = image
|
||||
? saveFileToDisk(image, "image", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
const imageFilename = IMAGE
|
||||
? saveFileToDisk(IMAGE, "IMAGE", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
|
||||
newExercise.VIDEO = videoFilename;
|
||||
newExercise.AUDIO = audioFilename;
|
||||
newExercise.IMAGE = imageFilename;
|
||||
await newExercise.save({ transaction });
|
||||
|
|
@ -111,14 +107,14 @@ export const createMatchingPairsExercise = async (req, res) => {
|
|||
} catch (error) {
|
||||
console.error(error);
|
||||
await transaction.rollback();
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const updateMatchingPairsExerciseById = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { ID_LEVEL, QUESTION, SCORE_WEIGHT } = req.body;
|
||||
const { ID_LEVEL, QUESTION, SCORE_WEIGHT, VIDEO } = req.body;
|
||||
let PAIRS = req.body.PAIRS;
|
||||
|
||||
try {
|
||||
|
|
@ -129,14 +125,14 @@ export const updateMatchingPairsExerciseById = async (req, res) => {
|
|||
return response(400, null, "Invalid PAIRS format", res);
|
||||
}
|
||||
|
||||
const { video, image, audio } = req.filesToSave || {};
|
||||
const { IMAGE, AUDIO } = req.filesToSave || {};
|
||||
|
||||
const transaction = await models.db.transaction();
|
||||
|
||||
try {
|
||||
const exercise = await models.Exercise.findByPk(id, { transaction });
|
||||
if (!exercise) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "Exercise not found", res);
|
||||
}
|
||||
|
|
@ -144,7 +140,7 @@ export const updateMatchingPairsExerciseById = async (req, res) => {
|
|||
if (ID_LEVEL) {
|
||||
const level = await models.Level.findByPk(ID_LEVEL, { transaction });
|
||||
if (!level) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
|
@ -153,26 +149,9 @@ export const updateMatchingPairsExerciseById = async (req, res) => {
|
|||
|
||||
if (QUESTION) exercise.QUESTION = QUESTION;
|
||||
if (SCORE_WEIGHT) exercise.SCORE_WEIGHT = SCORE_WEIGHT;
|
||||
if (VIDEO) exercise.VIDEO = VIDEO;
|
||||
|
||||
if (video) {
|
||||
if (exercise.VIDEO) {
|
||||
const oldVideoPath = path.join(
|
||||
"public/uploads/exercise/video",
|
||||
exercise.VIDEO
|
||||
);
|
||||
if (fs.existsSync(oldVideoPath)) {
|
||||
fs.unlinkSync(oldVideoPath);
|
||||
}
|
||||
}
|
||||
exercise.VIDEO = saveFileToDisk(
|
||||
video,
|
||||
"video",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
}
|
||||
|
||||
if (audio) {
|
||||
if (AUDIO) {
|
||||
if (exercise.AUDIO) {
|
||||
const oldAudioPath = path.join(
|
||||
"public/uploads/exercise/audio",
|
||||
|
|
@ -183,14 +162,14 @@ export const updateMatchingPairsExerciseById = async (req, res) => {
|
|||
}
|
||||
}
|
||||
exercise.AUDIO = saveFileToDisk(
|
||||
audio,
|
||||
"audio",
|
||||
AUDIO,
|
||||
"AUDIO",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
}
|
||||
|
||||
if (image) {
|
||||
if (IMAGE) {
|
||||
if (exercise.IMAGE) {
|
||||
const oldImagePath = path.join(
|
||||
"public/uploads/exercise/image",
|
||||
|
|
@ -201,8 +180,8 @@ export const updateMatchingPairsExerciseById = async (req, res) => {
|
|||
}
|
||||
}
|
||||
exercise.IMAGE = saveFileToDisk(
|
||||
image,
|
||||
"image",
|
||||
IMAGE,
|
||||
"IMAGE",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
|
|
@ -267,7 +246,7 @@ export const updateMatchingPairsExerciseById = async (req, res) => {
|
|||
} catch (error) {
|
||||
console.error(error);
|
||||
await transaction.rollback();
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ export const createMultipleChoicesExercise = async (req, res) => {
|
|||
OPTION_E,
|
||||
ANSWER_KEY,
|
||||
SCORE_WEIGHT,
|
||||
VIDEO,
|
||||
} = req.body;
|
||||
|
||||
const { video, image, audio } = req.filesToSave || {};
|
||||
const { IMAGE, AUDIO } = req.filesToSave || {};
|
||||
|
||||
if (!ID_LEVEL) return response(400, null, "Level ID is required", res);
|
||||
if (!QUESTION) return response(400, null, "Question is required", res);
|
||||
|
|
@ -39,7 +40,7 @@ export const createMultipleChoicesExercise = async (req, res) => {
|
|||
try {
|
||||
const level = await models.Level.findByPk(ID_LEVEL);
|
||||
if (!level) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ export const createMultipleChoicesExercise = async (req, res) => {
|
|||
where: { ID_LEVEL, TITLE: generatedTitle },
|
||||
});
|
||||
if (existingExercise) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
return response(
|
||||
400,
|
||||
null,
|
||||
|
|
@ -72,23 +73,19 @@ export const createMultipleChoicesExercise = async (req, res) => {
|
|||
SCORE_WEIGHT,
|
||||
QUESTION_TYPE: "MCQ",
|
||||
AUDIO: null,
|
||||
VIDEO: null,
|
||||
VIDEO: VIDEO || null,
|
||||
IMAGE: null,
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
|
||||
const videoFilename = video
|
||||
? saveFileToDisk(video, "video", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
const audioFilename = AUDIO
|
||||
? saveFileToDisk(AUDIO, "AUDIO", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
const audioFilename = audio
|
||||
? saveFileToDisk(audio, "audio", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
const imageFilename = image
|
||||
? saveFileToDisk(image, "image", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
const imageFilename = IMAGE
|
||||
? saveFileToDisk(IMAGE, "IMAGE", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
|
||||
newExercise.VIDEO = videoFilename;
|
||||
newExercise.AUDIO = audioFilename;
|
||||
newExercise.IMAGE = imageFilename;
|
||||
await newExercise.save({ transaction });
|
||||
|
|
@ -117,7 +114,7 @@ export const createMultipleChoicesExercise = async (req, res) => {
|
|||
} catch (error) {
|
||||
console.error(error);
|
||||
await transaction.rollback();
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
|
@ -134,9 +131,10 @@ export const updateMultipleChoicesExerciseById = async (req, res) => {
|
|||
OPTION_E,
|
||||
ANSWER_KEY,
|
||||
SCORE_WEIGHT,
|
||||
VIDEO,
|
||||
} = req.body;
|
||||
|
||||
const { video, image, audio } = req.filesToSave || {};
|
||||
const { IMAGE, AUDIO } = req.filesToSave || {};
|
||||
|
||||
const transaction = await models.db.transaction();
|
||||
|
||||
|
|
@ -144,7 +142,7 @@ export const updateMultipleChoicesExerciseById = async (req, res) => {
|
|||
const exercise = await models.Exercise.findByPk(id, { transaction });
|
||||
|
||||
if (!exercise) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "Exercise not found", res);
|
||||
}
|
||||
|
|
@ -152,7 +150,7 @@ export const updateMultipleChoicesExerciseById = async (req, res) => {
|
|||
if (ID_LEVEL) {
|
||||
const level = await models.Level.findByPk(ID_LEVEL, { transaction });
|
||||
if (!level) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
|
@ -161,26 +159,9 @@ export const updateMultipleChoicesExerciseById = async (req, res) => {
|
|||
|
||||
if (QUESTION) exercise.QUESTION = QUESTION;
|
||||
if (SCORE_WEIGHT) exercise.SCORE_WEIGHT = SCORE_WEIGHT;
|
||||
if (VIDEO) exercise.VIDEO = VIDEO;
|
||||
|
||||
if (video) {
|
||||
if (exercise.VIDEO) {
|
||||
const oldVideoPath = path.join(
|
||||
"public/uploads/exercise/video",
|
||||
exercise.VIDEO
|
||||
);
|
||||
if (fs.existsSync(oldVideoPath)) {
|
||||
fs.unlinkSync(oldVideoPath);
|
||||
}
|
||||
}
|
||||
exercise.VIDEO = saveFileToDisk(
|
||||
video,
|
||||
"video",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
}
|
||||
|
||||
if (audio) {
|
||||
if (AUDIO) {
|
||||
if (exercise.AUDIO) {
|
||||
const oldAudioPath = path.join(
|
||||
"public/uploads/exercise/audio",
|
||||
|
|
@ -191,14 +172,14 @@ export const updateMultipleChoicesExerciseById = async (req, res) => {
|
|||
}
|
||||
}
|
||||
exercise.AUDIO = saveFileToDisk(
|
||||
audio,
|
||||
"audio",
|
||||
AUDIO,
|
||||
"AUDIO",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
}
|
||||
|
||||
if (image) {
|
||||
if (IMAGE) {
|
||||
if (exercise.IMAGE) {
|
||||
const oldImagePath = path.join(
|
||||
"public/uploads/exercise/image",
|
||||
|
|
@ -209,8 +190,8 @@ export const updateMultipleChoicesExerciseById = async (req, res) => {
|
|||
}
|
||||
}
|
||||
exercise.IMAGE = saveFileToDisk(
|
||||
image,
|
||||
"image",
|
||||
IMAGE,
|
||||
"IMAGE",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
|
|
@ -224,7 +205,7 @@ export const updateMultipleChoicesExerciseById = async (req, res) => {
|
|||
});
|
||||
|
||||
if (!multipleChoices) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "Multiple Choices not found", res);
|
||||
}
|
||||
|
|
@ -248,7 +229,7 @@ export const updateMultipleChoicesExerciseById = async (req, res) => {
|
|||
response(200, payload, "Exercise updated successfully", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@ import fs from "fs";
|
|||
import path from "path";
|
||||
|
||||
export const createTrueFalseExercise = async (req, res) => {
|
||||
const { ID_LEVEL, TITLE, QUESTION, IS_TRUE, SCORE_WEIGHT } = req.body;
|
||||
|
||||
const { video, image, audio } = req.filesToSave || {};
|
||||
const { ID_LEVEL, TITLE, QUESTION, IS_TRUE, SCORE_WEIGHT, VIDEO } = req.body;
|
||||
const { IMAGE, AUDIO } = req.filesToSave || {};
|
||||
|
||||
if (!ID_LEVEL) return response(400, null, "Level ID is required", res);
|
||||
if (!QUESTION) return response(400, null, "Question is required", res);
|
||||
|
|
@ -24,7 +23,7 @@ export const createTrueFalseExercise = async (req, res) => {
|
|||
try {
|
||||
const level = await models.Level.findByPk(ID_LEVEL);
|
||||
if (!level) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +39,7 @@ export const createTrueFalseExercise = async (req, res) => {
|
|||
where: { ID_LEVEL, TITLE: generatedTitle },
|
||||
});
|
||||
if (existingExercise) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
return response(
|
||||
400,
|
||||
null,
|
||||
|
|
@ -57,23 +56,19 @@ export const createTrueFalseExercise = async (req, res) => {
|
|||
SCORE_WEIGHT,
|
||||
QUESTION_TYPE: "TFQ",
|
||||
AUDIO: null,
|
||||
VIDEO: null,
|
||||
VIDEO: VIDEO || null,
|
||||
IMAGE: null,
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
|
||||
const videoFilename = video
|
||||
? saveFileToDisk(video, "video", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
const audioFilename = AUDIO
|
||||
? saveFileToDisk(AUDIO, "AUDIO", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
const audioFilename = audio
|
||||
? saveFileToDisk(audio, "audio", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
const imageFilename = image
|
||||
? saveFileToDisk(image, "image", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
const imageFilename = IMAGE
|
||||
? saveFileToDisk(IMAGE, "IMAGE", ID_LEVEL, newExercise.ID_ADMIN_EXERCISE)
|
||||
: null;
|
||||
|
||||
newExercise.VIDEO = videoFilename;
|
||||
newExercise.AUDIO = audioFilename;
|
||||
newExercise.IMAGE = imageFilename;
|
||||
await newExercise.save({ transaction });
|
||||
|
|
@ -97,16 +92,15 @@ export const createTrueFalseExercise = async (req, res) => {
|
|||
} catch (error) {
|
||||
console.error(error);
|
||||
await transaction.rollback();
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const updateTrueFalseExerciseById = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { ID_LEVEL, QUESTION, IS_TRUE, SCORE_WEIGHT } = req.body;
|
||||
|
||||
const { video, image, audio } = req.filesToSave || {};
|
||||
const { ID_LEVEL, QUESTION, IS_TRUE, SCORE_WEIGHT, VIDEO } = req.body;
|
||||
const { IMAGE, AUDIO } = req.filesToSave || {};
|
||||
|
||||
const transaction = await models.db.transaction();
|
||||
|
||||
|
|
@ -114,7 +108,7 @@ export const updateTrueFalseExerciseById = async (req, res) => {
|
|||
const exercise = await models.Exercise.findByPk(id, { transaction });
|
||||
|
||||
if (!exercise) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "Exercise not found", res);
|
||||
}
|
||||
|
|
@ -122,7 +116,7 @@ export const updateTrueFalseExerciseById = async (req, res) => {
|
|||
if (ID_LEVEL) {
|
||||
const level = await models.Level.findByPk(ID_LEVEL, { transaction });
|
||||
if (!level) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
|
@ -131,26 +125,9 @@ export const updateTrueFalseExerciseById = async (req, res) => {
|
|||
|
||||
if (QUESTION) exercise.QUESTION = QUESTION;
|
||||
if (SCORE_WEIGHT) exercise.SCORE_WEIGHT = SCORE_WEIGHT;
|
||||
if (VIDEO) exercise.VIDEO = VIDEO;
|
||||
|
||||
if (video) {
|
||||
if (exercise.VIDEO) {
|
||||
const oldVideoPath = path.join(
|
||||
"public/uploads/exercise/video",
|
||||
exercise.VIDEO
|
||||
);
|
||||
if (fs.existsSync(oldVideoPath)) {
|
||||
fs.unlinkSync(oldVideoPath);
|
||||
}
|
||||
}
|
||||
exercise.VIDEO = saveFileToDisk(
|
||||
video,
|
||||
"video",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
}
|
||||
|
||||
if (audio) {
|
||||
if (AUDIO) {
|
||||
if (exercise.AUDIO) {
|
||||
const oldAudioPath = path.join(
|
||||
"public/uploads/exercise/audio",
|
||||
|
|
@ -161,14 +138,14 @@ export const updateTrueFalseExerciseById = async (req, res) => {
|
|||
}
|
||||
}
|
||||
exercise.AUDIO = saveFileToDisk(
|
||||
audio,
|
||||
"audio",
|
||||
AUDIO,
|
||||
"AUDIO",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
}
|
||||
|
||||
if (image) {
|
||||
if (IMAGE) {
|
||||
if (exercise.IMAGE) {
|
||||
const oldImagePath = path.join(
|
||||
"public/uploads/exercise/image",
|
||||
|
|
@ -179,8 +156,8 @@ export const updateTrueFalseExerciseById = async (req, res) => {
|
|||
}
|
||||
}
|
||||
exercise.IMAGE = saveFileToDisk(
|
||||
image,
|
||||
"image",
|
||||
IMAGE,
|
||||
"IMAGE",
|
||||
ID_LEVEL || exercise.ID_LEVEL,
|
||||
exercise.ID_ADMIN_EXERCISE
|
||||
);
|
||||
|
|
@ -194,7 +171,7 @@ export const updateTrueFalseExerciseById = async (req, res) => {
|
|||
});
|
||||
|
||||
if (!trueFalse) {
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "True/False exercise not found", res);
|
||||
}
|
||||
|
|
@ -215,8 +192,8 @@ export const updateTrueFalseExerciseById = async (req, res) => {
|
|||
response(200, payload, "True/False exercise updated successfully", res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
clearFileBuffers({ video, image, audio });
|
||||
clearFileBuffers({ IMAGE, AUDIO });
|
||||
await transaction.rollback();
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -129,7 +129,7 @@ export const getUserById = async (req, res) => {
|
|||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const user = await models.User.findByPk(id, {
|
||||
const userWithDetails = await models.User.findByPk(id, {
|
||||
attributes: {
|
||||
exclude: ["PASSWORD"],
|
||||
},
|
||||
|
|
@ -143,32 +143,45 @@ export const getUserById = async (req, res) => {
|
|||
model: models.Student,
|
||||
as: "students",
|
||||
attributes: ["NISN"],
|
||||
include: [
|
||||
{
|
||||
model: models.Class,
|
||||
as: "studentClass",
|
||||
attributes: ["NAME_CLASS"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
if (!userWithDetails) {
|
||||
return response(404, null, "User not found", res);
|
||||
}
|
||||
|
||||
let additionalField = null;
|
||||
if (user.ROLE === "teacher") {
|
||||
additionalField = { NIP: user.teachers.NIP };
|
||||
} else if (user.ROLE === "student") {
|
||||
additionalField = { NISN: user.students.NISN };
|
||||
if (userWithDetails.ROLE === "teacher") {
|
||||
additionalField = { NIP: userWithDetails.teachers.NIP };
|
||||
} else if (userWithDetails.ROLE === "student") {
|
||||
additionalField = {
|
||||
NISN: userWithDetails.students.NISN,
|
||||
NAME_CLASS: userWithDetails.students.studentClass
|
||||
? userWithDetails.students.studentClass.NAME_CLASS
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
const responseObject = {
|
||||
ID: user.ID,
|
||||
NAME_USERS: user.NAME_USERS,
|
||||
EMAIL: user.EMAIL,
|
||||
ROLE: user.ROLE,
|
||||
ID: userWithDetails.ID,
|
||||
NAME_USERS: userWithDetails.NAME_USERS,
|
||||
EMAIL: userWithDetails.EMAIL,
|
||||
ROLE: userWithDetails.ROLE,
|
||||
...additionalField,
|
||||
PICTURE: userWithDetails.PICTURE,
|
||||
};
|
||||
|
||||
response(200, responseObject, "Success", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.error(error);
|
||||
response(500, null, "Error retrieving user data!", res);
|
||||
}
|
||||
};
|
||||
|
|
@ -177,7 +190,7 @@ export const getUserByName = async (req, res) => {
|
|||
try {
|
||||
const { name } = req.params;
|
||||
|
||||
const user = await models.User.findOne({
|
||||
const userWithDetails = await models.User.findOne({
|
||||
where: { NAME_USERS: name },
|
||||
attributes: {
|
||||
exclude: ["PASSWORD"],
|
||||
|
|
@ -192,44 +205,57 @@ export const getUserByName = async (req, res) => {
|
|||
model: models.Student,
|
||||
as: "students",
|
||||
attributes: ["NISN"],
|
||||
include: [
|
||||
{
|
||||
model: models.Class,
|
||||
as: "studentClass",
|
||||
attributes: ["NAME_CLASS"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
if (!userWithDetails) {
|
||||
return response(404, null, "User not found", res);
|
||||
}
|
||||
|
||||
let additionalField = null;
|
||||
if (user.ROLE === "teacher" ) {
|
||||
additionalField = { NIP: user.teachers.NIP };
|
||||
} else if (user.ROLE === "student") {
|
||||
additionalField = { NISN: user.students.NISN };
|
||||
if (userWithDetails.ROLE === "teacher") {
|
||||
additionalField = { NIP: userWithDetails.teachers.NIP };
|
||||
} else if (userWithDetails.ROLE === "student") {
|
||||
additionalField = {
|
||||
NISN: userWithDetails.students.NISN,
|
||||
NAME_CLASS: userWithDetails.students.studentClass
|
||||
? userWithDetails.students.studentClass.NAME_CLASS
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
const responseObject = {
|
||||
ID: user.ID,
|
||||
NAME_USERS: user.NAME_USERS,
|
||||
EMAIL: user.EMAIL,
|
||||
ROLE: user.ROLE,
|
||||
ID: userWithDetails.ID,
|
||||
NAME_USERS: userWithDetails.NAME_USERS,
|
||||
EMAIL: userWithDetails.EMAIL,
|
||||
ROLE: userWithDetails.ROLE,
|
||||
...additionalField,
|
||||
PICTURE: userWithDetails.PICTURE,
|
||||
};
|
||||
|
||||
return response(200, responseObject, "Success", res);
|
||||
response(200, responseObject, "Success", res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return response(500, null, "Error retrieving user data!", res);
|
||||
console.error(error);
|
||||
response(500, null, "Error retrieving user data!", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const updateUserById = async (req, res) => {
|
||||
const transaction = await models.db.transaction();
|
||||
|
||||
const { picture } = req.filesToSave || {};
|
||||
const { PICTURE } = req.filesToSave || {};
|
||||
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { name, email, nip, nisn } = req.body;
|
||||
const { NAME_USERS, EMAIL, NIP, NISN } = req.body;
|
||||
|
||||
const user = await models.User.findByPk(id, {
|
||||
include: [
|
||||
|
|
@ -248,77 +274,77 @@ export const updateUserById = async (req, res) => {
|
|||
});
|
||||
|
||||
if (!user) {
|
||||
clearFileBuffers({ picture });
|
||||
clearFileBuffers({ PICTURE });
|
||||
await transaction.rollback();
|
||||
return response(404, null, "User not found", res);
|
||||
}
|
||||
|
||||
if (user.ROLE === "teacher" && nisn) {
|
||||
clearFileBuffers({ picture });
|
||||
if (user.ROLE === "teacher" && NISN) {
|
||||
clearFileBuffers({ PICTURE });
|
||||
await transaction.rollback();
|
||||
return response(400, null, "Role is teacher, but NISN is provided", res);
|
||||
}
|
||||
if (user.ROLE === "student" && nip) {
|
||||
clearFileBuffers({ picture });
|
||||
if (user.ROLE === "student" && NIP) {
|
||||
clearFileBuffers({ PICTURE });
|
||||
await transaction.rollback();
|
||||
return response(400, null, "Role is student, but NIP is provided", res);
|
||||
}
|
||||
|
||||
if (email && email !== user.EMAIL) {
|
||||
if (EMAIL && EMAIL !== user.EMAIL) {
|
||||
const emailExists = await models.User.findOne({
|
||||
where: { EMAIL: email },
|
||||
where: { EMAIL: EMAIL },
|
||||
transaction,
|
||||
});
|
||||
if (emailExists) {
|
||||
clearFileBuffers({ picture });
|
||||
clearFileBuffers({ PICTURE });
|
||||
await transaction.rollback();
|
||||
return response(400, null, "Email already in use", res);
|
||||
}
|
||||
user.EMAIL = email;
|
||||
user.EMAIL = EMAIL;
|
||||
}
|
||||
|
||||
user.NAME_USERS = name || user.NAME_USERS;
|
||||
user.NAME_USERS = NAME_USERS || user.NAME_USERS;
|
||||
|
||||
if (user.ROLE === "teacher" && nip) {
|
||||
if (user.ROLE === "teacher" && NIP) {
|
||||
let teacher = await models.Teacher.findOne({
|
||||
where: { ID: id },
|
||||
transaction,
|
||||
});
|
||||
if (teacher) {
|
||||
teacher.NIP = nip;
|
||||
teacher.NIP = NIP;
|
||||
await teacher.save({ transaction });
|
||||
} else {
|
||||
teacher = await models.Teacher.create(
|
||||
{ ID: id, NIP: nip },
|
||||
{ ID: id, NIP: NIP },
|
||||
{ transaction }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (user.ROLE === "student" && nisn) {
|
||||
if (user.ROLE === "student" && NISN) {
|
||||
let student = await models.Student.findOne({
|
||||
where: { ID: id },
|
||||
transaction,
|
||||
});
|
||||
if (student) {
|
||||
student.NISN = nisn;
|
||||
student.NISN = NISN;
|
||||
await student.save({ transaction });
|
||||
} else {
|
||||
student = await models.Student.create(
|
||||
{ ID: id, NISN: nisn },
|
||||
{ ID: id, NISN: NISN },
|
||||
{ transaction }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (picture) {
|
||||
if (PICTURE) {
|
||||
if (user.PICTURE) {
|
||||
const oldPicturePath = path.join("public/uploads/avatar", user.PICTURE);
|
||||
if (fs.existsSync(oldPicturePath)) {
|
||||
fs.unlinkSync(oldPicturePath);
|
||||
}
|
||||
}
|
||||
user.PICTURE = saveFileToDisk(picture, user.ID, user.NAME_USERS);
|
||||
user.PICTURE = saveFileToDisk(PICTURE, user.ID, user.NAME_USERS);
|
||||
}
|
||||
|
||||
await user.save({ transaction });
|
||||
|
|
@ -341,9 +367,23 @@ export const updateUserById = async (req, res) => {
|
|||
|
||||
await transaction.commit();
|
||||
|
||||
return response(200, user, "User updated successfully", res);
|
||||
let userResponse = {
|
||||
ID: user.ID,
|
||||
NAME_USERS: user.NAME_USERS,
|
||||
EMAIL: user.EMAIL,
|
||||
ROLE: user.ROLE,
|
||||
PICTURE: user.PICTURE,
|
||||
};
|
||||
|
||||
if (user.ROLE === "student" && user.students) {
|
||||
userResponse.NISN = user.students.NISN;
|
||||
} else if (user.ROLE === "teacher" && user.teachers) {
|
||||
userResponse.NIP = user.teachers.NIP;
|
||||
}
|
||||
|
||||
return response(200, userResponse, "User updated successfully", res);
|
||||
} catch (error) {
|
||||
clearFileBuffers({ picture });
|
||||
clearFileBuffers({ PICTURE });
|
||||
await transaction.rollback();
|
||||
console.log(error);
|
||||
return response(500, null, "Internal Server Error", res);
|
||||
|
|
@ -353,13 +393,13 @@ export const updateUserById = async (req, res) => {
|
|||
export const updateUserPasswordById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { oldPassword, password, confirmPassword } = req.body;
|
||||
const { OLD_PASSWORD, PASSWORD, CONFIRM_PASSWORD } = req.body;
|
||||
|
||||
if (!oldPassword || !password || !confirmPassword) {
|
||||
if (!OLD_PASSWORD || !PASSWORD || !CONFIRM_PASSWORD) {
|
||||
return response(400, null, "All fields must be filled.", res);
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
if (PASSWORD !== CONFIRM_PASSWORD) {
|
||||
return response(
|
||||
400,
|
||||
null,
|
||||
|
|
@ -373,13 +413,13 @@ export const updateUserPasswordById = async (req, res) => {
|
|||
return response(404, null, "User not found.", res);
|
||||
}
|
||||
|
||||
const isMatch = await bcrypt.compare(oldPassword, user.PASSWORD);
|
||||
const isMatch = await bcrypt.compare(OLD_PASSWORD, user.PASSWORD);
|
||||
if (!isMatch) {
|
||||
return response(400, null, "Incorrect old password.", res);
|
||||
}
|
||||
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const hashedPassword = await bcrypt.hash(password, salt);
|
||||
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
|
||||
|
||||
user.PASSWORD = hashedPassword;
|
||||
await user.save();
|
||||
|
|
@ -422,23 +462,29 @@ export const deleteUserById = async (req, res) => {
|
|||
|
||||
export const getMe = async (req, res) => {
|
||||
try {
|
||||
const user = req.user; // User object from verifyLoginUser middleware
|
||||
const user = req.user;
|
||||
|
||||
// Retrieve teacher or student details based on the user's role
|
||||
const userWithDetails = await models.User.findByPk(user.ID, {
|
||||
attributes: {
|
||||
exclude: ["PASSWORD"], // Exclude sensitive information
|
||||
exclude: ["PASSWORD"],
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: models.Teacher,
|
||||
as: "teachers",
|
||||
attributes: ["NIP"], // Include NIP for teacher
|
||||
attributes: ["NIP"],
|
||||
},
|
||||
{
|
||||
model: models.Student,
|
||||
as: "students",
|
||||
attributes: ["NISN"], // Include NISN for student
|
||||
attributes: ["NISN"],
|
||||
include: [
|
||||
{
|
||||
model: models.Class,
|
||||
as: "studentClass",
|
||||
attributes: ["NAME_CLASS"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -447,27 +493,30 @@ export const getMe = async (req, res) => {
|
|||
return response(404, null, "User not found", res);
|
||||
}
|
||||
|
||||
// Determine additional field based on user role
|
||||
let additionalField = null;
|
||||
if (userWithDetails.ROLE === "teacher") {
|
||||
additionalField = { NIP: userWithDetails.teachers.NIP };
|
||||
} else if (userWithDetails.ROLE === "student") {
|
||||
additionalField = { NISN: userWithDetails.students.NISN };
|
||||
additionalField = {
|
||||
NISN: userWithDetails.students.NISN,
|
||||
NAME_CLASS: userWithDetails.students.studentClass
|
||||
? userWithDetails.students.studentClass.NAME_CLASS
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
// Construct the response object
|
||||
const responseObject = {
|
||||
ID: userWithDetails.ID,
|
||||
NAME_USERS: userWithDetails.NAME_USERS,
|
||||
EMAIL: userWithDetails.EMAIL,
|
||||
ROLE: userWithDetails.ROLE,
|
||||
...additionalField,
|
||||
PICTURE: userWithDetails.PICTURE,
|
||||
};
|
||||
|
||||
// Send the response
|
||||
response(200, responseObject, "Success", res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
response(500, null, "Error retrieving user data!", res);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,20 +10,7 @@ const fileFilter = (req, file, cb) => {
|
|||
const ext = path.extname(file.originalname).toLowerCase();
|
||||
|
||||
switch (file.fieldname) {
|
||||
case "video":
|
||||
if (ext === ".mp4") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(
|
||||
new Error(
|
||||
"Invalid file type, only .mp4 files are allowed for video!"
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "audio":
|
||||
case "AUDIO":
|
||||
if (ext === ".mp3") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
|
|
@ -36,7 +23,7 @@ const fileFilter = (req, file, cb) => {
|
|||
}
|
||||
break;
|
||||
|
||||
case "image":
|
||||
case "IMAGE":
|
||||
if (ext === ".jpg" || ext === ".jpeg" || ext === ".png") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
|
|
@ -61,9 +48,8 @@ const upload = multer({
|
|||
fileSize: 100 * 1024 * 1024,
|
||||
},
|
||||
}).fields([
|
||||
{ name: "video", maxCount: 1 },
|
||||
{ name: "audio", maxCount: 1 },
|
||||
{ name: "image", maxCount: 1 },
|
||||
{ name: "AUDIO", maxCount: 1 },
|
||||
{ name: "IMAGE", maxCount: 1 },
|
||||
]);
|
||||
|
||||
const handleUpload = (req, res, next) => {
|
||||
|
|
@ -73,42 +59,35 @@ const handleUpload = (req, res, next) => {
|
|||
}
|
||||
|
||||
const files = req.files;
|
||||
const video = files?.video ? files.video[0] : null;
|
||||
const audio = files?.audio ? files.audio[0] : null;
|
||||
const image = files?.image ? files.image[0] : null;
|
||||
const AUDIO = files?.AUDIO ? files.AUDIO[0] : null;
|
||||
const IMAGE = files?.IMAGE ? files.IMAGE[0] : null;
|
||||
|
||||
try {
|
||||
let validFiles = true;
|
||||
let errorMessages = [];
|
||||
|
||||
if (video && video.size > 30 * 1024 * 1024) {
|
||||
if (AUDIO && AUDIO.size > 10 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
video.buffer = null;
|
||||
errorMessages.push("Video file exceeds the size limit of 30MB");
|
||||
}
|
||||
|
||||
if (audio && audio.size > 10 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
audio.buffer = null;
|
||||
AUDIO.buffer = null;
|
||||
errorMessages.push("Audio file exceeds the size limit of 10MB");
|
||||
}
|
||||
|
||||
if (image && image.size > 5 * 1024 * 1024) {
|
||||
if (IMAGE && IMAGE.size > 5 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
image.buffer = null;
|
||||
IMAGE.buffer = null;
|
||||
errorMessages.push("Image file exceeds the size limit of 5MB");
|
||||
}
|
||||
|
||||
if (validFiles) {
|
||||
req.filesToSave = { video, audio, image };
|
||||
req.filesToSave = { AUDIO, IMAGE };
|
||||
next();
|
||||
} else {
|
||||
clearFileBuffers({ video, audio, image });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(400, null, errorMessages.join("; "), res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
clearFileBuffers({ video, audio, image });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
});
|
||||
|
|
@ -136,13 +115,10 @@ export const saveFileToDisk = (file, type, topicId, sectionId, levelId) => {
|
|||
|
||||
let folderPath;
|
||||
switch (type) {
|
||||
case "video":
|
||||
folderPath = path.join("public/uploads/level/video");
|
||||
break;
|
||||
case "audio":
|
||||
case "AUDIO":
|
||||
folderPath = path.join("public/uploads/level/audio");
|
||||
break;
|
||||
case "image":
|
||||
case "IMAGE":
|
||||
folderPath = path.join("public/uploads/level/image");
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export const verifyLoginUser = async (req, res, next) => {
|
|||
try {
|
||||
const decoded = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
|
||||
|
||||
const user = await models.User.findByPk(decoded.id, {
|
||||
const user = await models.User.findByPk(decoded.ID, {
|
||||
attributes: {
|
||||
exclude: ["PASSWORD"],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const upload = multer({
|
|||
storage: memoryStorage,
|
||||
fileFilter,
|
||||
limits: { fileSize: 5 * 1024 * 1024 },
|
||||
}).fields([{ name: "picture", maxCount: 1 }]);
|
||||
}).fields([{ name: "PICTURE", maxCount: 1 }]);
|
||||
|
||||
const handleUpload = (req, res, next) => {
|
||||
upload(req, res, (err) => {
|
||||
|
|
@ -33,23 +33,23 @@ const handleUpload = (req, res, next) => {
|
|||
}
|
||||
|
||||
const files = req.files;
|
||||
const picture = files?.picture ? files.picture[0] : null;
|
||||
const PICTURE = files?.PICTURE ? files.PICTURE[0] : null;
|
||||
|
||||
try {
|
||||
let validFiles = true;
|
||||
let errorMessages = [];
|
||||
|
||||
if (picture && picture.size > 5 * 1024 * 1024) {
|
||||
if (PICTURE && PICTURE.size > 5 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
picture.buffer = null;
|
||||
PICTURE.buffer = null;
|
||||
errorMessages.push("Picture file exceeds the size limit of 5MB");
|
||||
}
|
||||
|
||||
if (validFiles) {
|
||||
req.filesToSave = { picture };
|
||||
req.filesToSave = { PICTURE };
|
||||
next();
|
||||
} else {
|
||||
clearFileBuffers({ picture });
|
||||
clearFileBuffers({ PICTURE });
|
||||
return response(400, null, errorMessages.join(", "), res);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -10,20 +10,7 @@ const fileFilter = (req, file, cb) => {
|
|||
const ext = path.extname(file.originalname).toLowerCase();
|
||||
|
||||
switch (file.fieldname) {
|
||||
case "video":
|
||||
if (ext === ".mp4") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(
|
||||
new Error(
|
||||
"Invalid file type, only .mp4 files are allowed for video!"
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "audio":
|
||||
case "AUDIO":
|
||||
if (ext === ".mp3") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
|
|
@ -36,7 +23,7 @@ const fileFilter = (req, file, cb) => {
|
|||
}
|
||||
break;
|
||||
|
||||
case "image":
|
||||
case "IMAGE":
|
||||
if (ext === ".jpg" || ext === ".jpeg" || ext === ".png") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
|
|
@ -61,9 +48,8 @@ const upload = multer({
|
|||
fileSize: 100 * 1024 * 1024,
|
||||
},
|
||||
}).fields([
|
||||
{ name: "video", maxCount: 1 },
|
||||
{ name: "audio", maxCount: 1 },
|
||||
{ name: "image", maxCount: 1 },
|
||||
{ name: "AUDIO", maxCount: 1 },
|
||||
{ name: "IMAGE", maxCount: 1 },
|
||||
]);
|
||||
|
||||
const handleUpload = (req, res, next) => {
|
||||
|
|
@ -73,42 +59,35 @@ const handleUpload = (req, res, next) => {
|
|||
}
|
||||
|
||||
const files = req.files;
|
||||
const video = files?.video ? files.video[0] : null;
|
||||
const audio = files?.audio ? files.audio[0] : null;
|
||||
const image = files?.image ? files.image[0] : null;
|
||||
const AUDIO = files?.AUDIO ? files.AUDIO[0] : null;
|
||||
const IMAGE = files?.IMAGE ? files.IMAGE[0] : null;
|
||||
|
||||
try {
|
||||
let validFiles = true;
|
||||
let errorMessages = [];
|
||||
|
||||
if (video && video.size > 30 * 1024 * 1024) {
|
||||
if (AUDIO && AUDIO.size > 10 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
video.buffer = null;
|
||||
errorMessages.push("Video file exceeds the size limit of 30MB");
|
||||
}
|
||||
|
||||
if (audio && audio.size > 10 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
audio.buffer = null;
|
||||
AUDIO.buffer = null;
|
||||
errorMessages.push("Audio file exceeds the size limit of 10MB");
|
||||
}
|
||||
|
||||
if (image && image.size > 5 * 1024 * 1024) {
|
||||
if (IMAGE && IMAGE.size > 5 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
image.buffer = null;
|
||||
IMAGE.buffer = null;
|
||||
errorMessages.push("Image file exceeds the size limit of 5MB");
|
||||
}
|
||||
|
||||
if (validFiles) {
|
||||
req.filesToSave = { video, audio, image };
|
||||
req.filesToSave = { AUDIO, IMAGE };
|
||||
next();
|
||||
} else {
|
||||
clearFileBuffers({ video, audio, image });
|
||||
clearFileBuffers({ AUDIO, IMAGE });
|
||||
return response(400, null, errorMessages.join("; "), res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
clearFileBuffers({ video, audio, image });
|
||||
clearFileBuffers({ video, AUDIO, IMAGE });
|
||||
return response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
});
|
||||
|
|
@ -136,13 +115,10 @@ export const saveFileToDisk = (file, type, levelId, exerciseId) => {
|
|||
|
||||
let folderPath;
|
||||
switch (type) {
|
||||
case "video":
|
||||
folderPath = path.join("public/uploads/exercise/video");
|
||||
break;
|
||||
case "audio":
|
||||
case "AUDIO":
|
||||
folderPath = path.join("public/uploads/exercise/audio");
|
||||
break;
|
||||
case "image":
|
||||
case "IMAGE":
|
||||
folderPath = path.join("public/uploads/exercise/image");
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const upload = multer({
|
|||
storage: memoryStorage,
|
||||
fileFilter,
|
||||
limits: { fileSize: 5 * 1024 * 1024 },
|
||||
}).fields([{ name: "thumbnail", maxCount: 1 }]);
|
||||
}).fields([{ name: "THUMBNAIL", maxCount: 1 }]);
|
||||
|
||||
const handleUpload = (req, res, next) => {
|
||||
upload(req, res, (err) => {
|
||||
|
|
@ -33,28 +33,28 @@ const handleUpload = (req, res, next) => {
|
|||
}
|
||||
|
||||
const files = req.files;
|
||||
const thumbnail = files?.thumbnail ? files.thumbnail[0] : null;
|
||||
const THUMBNAIL = files?.THUMBNAIL ? files.THUMBNAIL[0] : null;
|
||||
|
||||
try {
|
||||
let validFiles = true;
|
||||
let errorMessages = [];
|
||||
|
||||
if (thumbnail && thumbnail.size > 5 * 1024 * 1024) {
|
||||
if (THUMBNAIL && THUMBNAIL.size > 5 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
thumbnail.buffer = null;
|
||||
THUMBNAIL.buffer = null;
|
||||
errorMessages.push("Thumbnail file exceeds the size limit of 5MB");
|
||||
}
|
||||
|
||||
if (validFiles) {
|
||||
req.filesToSave = { thumbnail };
|
||||
req.filesToSave = { THUMBNAIL };
|
||||
next();
|
||||
} else {
|
||||
clearFileBuffers({ thumbnail });
|
||||
clearFileBuffers({ THUMBNAIL });
|
||||
return response(400, null, errorMessages.join(", "), res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
clearFileBuffers({ thumbnail });
|
||||
clearFileBuffers({ THUMBNAIL });
|
||||
return response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,6 +37,13 @@ const TopicModel = (DataTypes) => {
|
|||
notEmpty: true,
|
||||
},
|
||||
},
|
||||
OBJECTIVES: {
|
||||
type: DataTypes.STRING(1024),
|
||||
allowNull: false,
|
||||
validate: {
|
||||
notEmpty: true,
|
||||
},
|
||||
},
|
||||
TIME_TOPIC: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
|
|
|
|||
BIN
public/uploads/avatar/user-8087dbf0bf98571ae2d8db93f96c51b3.jpeg
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
public/uploads/avatar/user-899f0c3a99d44dc1c8ba0ef5b9313b9d.jpeg
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
public/uploads/avatar/user-d3b55e105e3f6aaae08de98c6d4fb98d.jpeg
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -1,5 +1,5 @@
|
|||
import express from "express";
|
||||
import { getExercises, getExercisesForAdmin, getExerciseById, deleteExerciseById, deleteExerciseFileById } from "../../controllers/contentControllers/exercise.js";
|
||||
import { getExercises, getExercisesForAdmin, getExerciseById, getExerciseByLevelId, deleteExerciseById, deleteExerciseFileById } from "../../controllers/contentControllers/exercise.js";
|
||||
import { createMultipleChoicesExercise, updateMultipleChoicesExerciseById } from "../../controllers/exerciseTypesControllers/multipleChoices.js";
|
||||
import { createMatchingPairsExercise, updateMatchingPairsExerciseById } from "../../controllers/exerciseTypesControllers/matchingPairs.js";
|
||||
import { createTrueFalseExercise, updateTrueFalseExerciseById } from "../../controllers/exerciseTypesControllers/trueFalse.js";
|
||||
|
|
@ -13,6 +13,8 @@ router.get("/exercise", verifyLoginUser, getExercises);
|
|||
|
||||
router.get("/exercise/admin", verifyLoginUser, adminOnly, getExercisesForAdmin);
|
||||
|
||||
router.get("/exercise/level/:idLevel", verifyLoginUser, getExerciseByLevelId);
|
||||
|
||||
router.get("/exercise/:id", verifyLoginUser, getExerciseById);
|
||||
|
||||
router.post("/exercise/multiple-choices", verifyLoginUser, adminOnly, handleUpload, createMultipleChoicesExercise);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import express from "express";
|
||||
// import { getAllLevels, getAllLevelById, getLevels, getLevelById, createLevel, updateLevelById, deleteLevelById, getRoutes, getRouteById, updateRouteById } from "../controllers/level.js";
|
||||
import { getLevels, getLevelById, createLevel, updateLevelById, deleteLevelById } from "../../controllers/contentControllers/level.js";
|
||||
import { getLevels, getLevelById, getLevelsByTopicId, createLevel, updateLevelById, deleteLevelById, getPreviousLevel } from "../../controllers/contentControllers/level.js";
|
||||
import { verifyLoginUser, adminOnly } from "../../middlewares/User/authUser.js";
|
||||
import handleUpload from '../../middlewares/Level/uploadLevel.js';
|
||||
import {checkLevelsPerTopic, autoCalculateRoutes, getSectionAndTopicByLevelId } from '../../middlewares/Level/checkLevel.js';
|
||||
|
|
@ -8,14 +7,14 @@ import {checkLevelsPerTopic, autoCalculateRoutes, getSectionAndTopicByLevelId }
|
|||
|
||||
const router = express.Router();
|
||||
|
||||
// router.get("/levels", verifyLoginUser, adminOnly, getAllLevels);
|
||||
|
||||
// router.get("/levels/:id", verifyLoginUser, adminOnly, getAllLevelById);
|
||||
|
||||
router.get("/level", verifyLoginUser, getLevels);
|
||||
|
||||
router.get("/level/topic/:idTopic", verifyLoginUser, getLevelsByTopicId);
|
||||
|
||||
router.get("/level/:id", verifyLoginUser, getLevelById);
|
||||
|
||||
router.get("/previous/level/:next_learning", verifyLoginUser, getPreviousLevel);
|
||||
|
||||
router.post("/level", verifyLoginUser, adminOnly, handleUpload, checkLevelsPerTopic, autoCalculateRoutes, createLevel);
|
||||
|
||||
router.put("/level/:id", verifyLoginUser, adminOnly, handleUpload, getSectionAndTopicByLevelId, autoCalculateRoutes, updateLevelById);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import express from "express";
|
||||
import { getTopics, getTopicById, createTopic, updateTopicById, deleteTopicById } from "../../controllers/contentControllers/topic.js";
|
||||
import { getTopics, getTopicById, getTopicBySectionId, createTopic, updateTopicById, deleteTopicById, getCompletedTopics } from "../../controllers/contentControllers/topic.js";
|
||||
import { verifyLoginUser, adminOnly } from "../../middlewares/User/authUser.js";
|
||||
|
||||
|
||||
|
|
@ -7,6 +7,10 @@ const router = express.Router();
|
|||
|
||||
router.get("/topic", verifyLoginUser, getTopics);
|
||||
|
||||
router.get("/topic/complete", verifyLoginUser, getCompletedTopics);
|
||||
|
||||
router.get("/topic/section/:sectionId", verifyLoginUser, getTopicBySectionId);
|
||||
|
||||
router.get("/topic/:id", verifyLoginUser, getTopicById);
|
||||
|
||||
router.post("/topic", verifyLoginUser, adminOnly, createTopic);
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ router.get("/user/name/:name", verifyLoginUser, adminOrTeacherOnly, getUserByNam
|
|||
|
||||
router.get("/getMe", verifyLoginUser, getMe);
|
||||
|
||||
router.post("/user/update/:id", verifyLoginUser, handleUpload, updateUserById);
|
||||
router.put("/user/update/:id", verifyLoginUser, handleUpload, updateUserById);
|
||||
|
||||
router.post("/user/update/password/:id", verifyLoginUser, updateUserPasswordById);
|
||||
router.put("/user/update/password/:id", verifyLoginUser, updateUserPasswordById);
|
||||
|
||||
router.delete("/user/delete/:id", verifyLoginUser, adminOnly, deleteUserById);
|
||||
|
||||
|
|
|
|||