feat: upload, get, and delete level file function
This commit is contained in:
parent
411f392e24
commit
2e669bc281
|
|
@ -716,6 +716,54 @@ export const deleteLevelFileById = async (req, res) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const deleteLevelFilesById = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { fileName } = req.body;
|
||||
|
||||
const filePattern =
|
||||
/^(AUDIO|IMAGE)-([a-f0-9-]{36})-[a-f0-9]{32}\.(mp3|jpg|jpeg|png)$/;
|
||||
const match = fileName.match(filePattern);
|
||||
|
||||
if (!match) {
|
||||
return response(400, null, "Invalid file name format", res);
|
||||
}
|
||||
|
||||
const fileType = match[1];
|
||||
const levelIdFromFile = match[2];
|
||||
|
||||
if (levelIdFromFile !== id) {
|
||||
return response(400, null, "Level ID in file name does not match", res);
|
||||
}
|
||||
|
||||
try {
|
||||
const level = await models.Level.findByPk(id);
|
||||
|
||||
if (!level) {
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
||||
let filePath;
|
||||
|
||||
if (fileType === "AUDIO") {
|
||||
filePath = path.join("public/uploads/level/audio", fileName);
|
||||
} else if (fileType === "IMAGE") {
|
||||
filePath = path.join("public/uploads/level/image", fileName);
|
||||
} else {
|
||||
return response(400, null, "Invalid file type", res);
|
||||
}
|
||||
|
||||
if (filePath && fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
return response(200, null, `${fileType} file deleted successfully`, res);
|
||||
} else {
|
||||
return response(404, null, "File not found on the server", res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
response(500, null, "Internal Server Error", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const getPreviousLevel = async (req, res) => {
|
||||
try {
|
||||
const { next_learning } = req.params;
|
||||
|
|
@ -874,3 +922,96 @@ export const getPreviousLevel = async (req, res) => {
|
|||
res.status(500).json({ message: "Internal Server Error" });
|
||||
}
|
||||
};
|
||||
|
||||
export const uploadLevelFile = async (req, res) => {
|
||||
const { levelId } = req.params;
|
||||
|
||||
try {
|
||||
const level = await models.Level.findByPk(levelId);
|
||||
|
||||
if (!level) {
|
||||
return response(404, null, "Level not found", res);
|
||||
}
|
||||
|
||||
const filesToSave = req.filesToSave;
|
||||
|
||||
if (!filesToSave || Object.keys(filesToSave).length === 0) {
|
||||
return response(400, null, "No files to upload", res);
|
||||
}
|
||||
|
||||
const { ID_TOPIC, ID_SECTION } = level;
|
||||
const savedFiles = {};
|
||||
|
||||
Object.keys(filesToSave).forEach((key) => {
|
||||
let filename;
|
||||
if (key.startsWith("AUDIO")) {
|
||||
const audioFile = filesToSave[key];
|
||||
filename = saveFileToDisk(
|
||||
audioFile,
|
||||
"AUDIO",
|
||||
ID_TOPIC,
|
||||
ID_SECTION,
|
||||
levelId
|
||||
);
|
||||
} else if (key.startsWith("IMAGE")) {
|
||||
const imageFile = filesToSave[key];
|
||||
filename = saveFileToDisk(
|
||||
imageFile,
|
||||
"IMAGE",
|
||||
ID_TOPIC,
|
||||
ID_SECTION,
|
||||
levelId
|
||||
);
|
||||
}
|
||||
|
||||
if (filename) {
|
||||
savedFiles[key] = filename;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(savedFiles).length === 0) {
|
||||
return response(400, null, "Failed to save files", res);
|
||||
}
|
||||
|
||||
return response(200, savedFiles, "Files uploaded successfully", res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return response(500, null, "Internal server error", res);
|
||||
}
|
||||
};
|
||||
|
||||
export const getLevelFiles = async (req, res) => {
|
||||
const { levelId } = req.params;
|
||||
|
||||
try {
|
||||
const audioFolderPath = path.join("public/uploads/level/audio");
|
||||
const imageFolderPath = path.join("public/uploads/level/image");
|
||||
|
||||
const getFilesByLevelId = (folderPath, fileType) => {
|
||||
if (fs.existsSync(folderPath)) {
|
||||
const files = fs.readdirSync(folderPath);
|
||||
return files.filter((file) =>
|
||||
file.startsWith(`${fileType}-${levelId}`)
|
||||
);
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
const audioFiles = getFilesByLevelId(audioFolderPath, "AUDIO");
|
||||
const imageFiles = getFilesByLevelId(imageFolderPath, "IMAGE");
|
||||
|
||||
if (audioFiles.length === 0 && imageFiles.length === 0) {
|
||||
return response(404, null, "No files found for this level", res);
|
||||
}
|
||||
|
||||
const levelFiles = {
|
||||
audioFiles,
|
||||
imageFiles,
|
||||
};
|
||||
|
||||
return response(200, levelFiles, "Files retrieved successfully", res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return response(500, null, "Internal server error", res);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
137
middlewares/Level/uploadLevelFile.js
Normal file
137
middlewares/Level/uploadLevelFile.js
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
import multer from "multer";
|
||||
import crypto from "crypto";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import response from "../../response.js";
|
||||
|
||||
const memoryStorage = multer.memoryStorage();
|
||||
|
||||
const fileFilter = (req, file, cb) => {
|
||||
const ext = path.extname(file.originalname).toLowerCase();
|
||||
|
||||
if (file.fieldname.startsWith("AUDIO")) {
|
||||
if (ext === ".mp3") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(
|
||||
new Error("Invalid file type, only .mp3 files are allowed for audio!"),
|
||||
false
|
||||
);
|
||||
}
|
||||
} else if (file.fieldname.startsWith("IMAGE")) {
|
||||
if (ext === ".jpg" || ext === ".jpeg" || ext === ".png") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(
|
||||
new Error(
|
||||
"Invalid file type, only .jpg, .jpeg, and .png files are allowed for image!"
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
} else {
|
||||
cb(new Error("Invalid file type!"), false);
|
||||
}
|
||||
};
|
||||
|
||||
const upload = multer({
|
||||
storage: memoryStorage,
|
||||
fileFilter,
|
||||
limits: {
|
||||
fileSize: 100 * 1024 * 1024,
|
||||
},
|
||||
}).any();
|
||||
|
||||
const handleUploadFile = (req, res, next) => {
|
||||
upload(req, res, (err) => {
|
||||
if (err) {
|
||||
return response(400, null, err.message, res);
|
||||
}
|
||||
|
||||
const files = req.files || [];
|
||||
req.filesToSave = {};
|
||||
|
||||
let validFiles = true;
|
||||
let errorMessages = [];
|
||||
|
||||
files.forEach((file) => {
|
||||
if (file.fieldname.startsWith("AUDIO")) {
|
||||
if (file.size > 10 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
errorMessages.push(`Audio file exceeds the size limit of 10MB`);
|
||||
} else {
|
||||
req.filesToSave[file.fieldname] = file;
|
||||
}
|
||||
} else if (file.fieldname.startsWith("IMAGE")) {
|
||||
if (file.size > 5 * 1024 * 1024) {
|
||||
validFiles = false;
|
||||
errorMessages.push(`Image file exceeds the size limit of 5MB`);
|
||||
} else {
|
||||
req.filesToSave[file.fieldname] = file;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (validFiles) {
|
||||
next();
|
||||
} else {
|
||||
clearFileBuffers(req.filesToSave);
|
||||
return response(400, null, errorMessages.join("; "), res);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const clearFileBuffers = (files) => {
|
||||
for (const file of Object.values(files)) {
|
||||
if (file && file.buffer) {
|
||||
file.buffer = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const generateHash = (
|
||||
levelId,
|
||||
sectionId,
|
||||
topicId,
|
||||
filename,
|
||||
bufferLength
|
||||
) => {
|
||||
return crypto
|
||||
.createHash("md5")
|
||||
.update(levelId + sectionId + topicId + filename + bufferLength)
|
||||
.digest("hex");
|
||||
};
|
||||
|
||||
export const saveFileToDisk = (file, type, topicId, sectionId, levelId) => {
|
||||
const ext = path.extname(file.originalname);
|
||||
const hash = generateHash(
|
||||
levelId,
|
||||
sectionId,
|
||||
topicId,
|
||||
file.originalname,
|
||||
file.buffer.length
|
||||
);
|
||||
const filename = `${type}-${levelId}-${hash}${ext}`;
|
||||
|
||||
let folderPath;
|
||||
switch (type) {
|
||||
case "AUDIO":
|
||||
folderPath = path.join("public/uploads/level/audio");
|
||||
break;
|
||||
case "IMAGE":
|
||||
folderPath = path.join("public/uploads/level/image");
|
||||
break;
|
||||
default:
|
||||
folderPath = path.join("public/uploads/level");
|
||||
}
|
||||
|
||||
if (!fs.existsSync(folderPath)) {
|
||||
fs.mkdirSync(folderPath, { recursive: true });
|
||||
}
|
||||
|
||||
const filepath = path.join(folderPath, filename);
|
||||
fs.writeFileSync(filepath, file.buffer);
|
||||
return filename;
|
||||
};
|
||||
|
||||
export default handleUploadFile;
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
|
|
@ -1,7 +1,8 @@
|
|||
import express from "express";
|
||||
import { getLevels, getLevelById, getLevelForAdmin, getLevelsByTopicId, createLevel, updateLevelById, deleteLevelById, deleteLevelFileById, getPreviousLevel } from "../../controllers/contentControllers/level.js";
|
||||
import { getLevels, getLevelById, getLevelForAdmin, getLevelsByTopicId, createLevel, updateLevelById, deleteLevelById, deleteLevelFilesById, getPreviousLevel, uploadLevelFile, getLevelFiles } from "../../controllers/contentControllers/level.js";
|
||||
import { verifyLoginUser, adminOnly } from "../../middlewares/User/authUser.js";
|
||||
import handleUpload from '../../middlewares/Level/uploadLevel.js';
|
||||
import handleUploadFile from "../../middlewares/Level/uploadLevelFile.js";
|
||||
import {checkLevelsPerTopic, autoCalculateRoutes, getSectionAndTopicByLevelId } from '../../middlewares/Level/checkLevel.js';
|
||||
|
||||
|
||||
|
|
@ -17,12 +18,18 @@ router.get("/level/:id", verifyLoginUser, getLevelById);
|
|||
|
||||
router.get("/previous/level/:next_learning", verifyLoginUser, getPreviousLevel);
|
||||
|
||||
router.get("/level/file/:levelId", verifyLoginUser, getLevelFiles);
|
||||
|
||||
router.post("/level", verifyLoginUser, adminOnly, handleUpload, checkLevelsPerTopic, autoCalculateRoutes, createLevel);
|
||||
|
||||
router.post("/level/file/:levelId", verifyLoginUser, adminOnly, handleUploadFile, uploadLevelFile);
|
||||
|
||||
router.put("/level/:id", verifyLoginUser, adminOnly, handleUpload, getSectionAndTopicByLevelId, autoCalculateRoutes, updateLevelById);
|
||||
|
||||
router.delete("/level/:id", verifyLoginUser, adminOnly, getSectionAndTopicByLevelId, deleteLevelById);
|
||||
|
||||
router.delete("/level/file/:id", verifyLoginUser, adminOnly, deleteLevelFileById);
|
||||
// router.delete("/level/file/:id", verifyLoginUser, adminOnly, deleteLevelFileById);
|
||||
|
||||
router.delete("/level/file/:id", verifyLoginUser, adminOnly, deleteLevelFilesById);
|
||||
|
||||
export default router
|
||||
Loading…
Reference in New Issue
Block a user