refactor: user model function and exercises

This commit is contained in:
elangptra 2024-09-19 17:04:18 +07:00
parent 56dad54d89
commit 40e8ca4a44
41 changed files with 802 additions and 457 deletions

View File

@ -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();

View File

@ -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,

View File

@ -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" });
}
};

View File

@ -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);
}
};

View File

@ -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);
}
};

View File

@ -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);
}
};

View File

@ -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);
}

View File

@ -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);
}
};
};

View File

@ -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);
}
};
};

View File

@ -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:

View File

@ -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"],
},

View File

@ -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) {

View File

@ -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:

View File

@ -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);
}
});

View File

@ -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,

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);