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(); switch (file.fieldname) { case "AUDIO": if (ext === ".mp3") { cb(null, true); } else { cb( new Error( "Invalid file type, only .mp3 files are allowed for audio!" ), false ); } break; case "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 ); } break; default: cb(new Error("Invalid file type!"), false); } }; const upload = multer({ storage: memoryStorage, fileFilter, limits: { fileSize: 100 * 1024 * 1024, }, }).fields([ { name: "AUDIO", maxCount: 1 }, { name: "IMAGE", maxCount: 1 }, ]); const handleUploadSingleExercise = (req, res, next) => { upload(req, res, (err) => { if (err) { return response(400, null, err.message, res); } const files = req.files; const AUDIO = files?.AUDIO ? files.AUDIO[0] : null; const IMAGE = files?.IMAGE ? files.IMAGE[0] : null; try { let validFiles = true; let errorMessages = []; if (AUDIO && AUDIO.size > 10 * 1024 * 1024) { validFiles = false; AUDIO.buffer = null; errorMessages.push("Audio file exceeds the size limit of 10MB"); } if (IMAGE && IMAGE.size > 5 * 1024 * 1024) { validFiles = false; IMAGE.buffer = null; errorMessages.push("Image file exceeds the size limit of 5MB"); } if (validFiles) { req.filesToSave = { AUDIO, IMAGE }; next(); } else { clearFileBuffers({ AUDIO, IMAGE }); return response(400, null, errorMessages.join("; "), res); } } catch (error) { console.log(error); clearFileBuffers({ video, AUDIO, IMAGE }); return response(500, null, "Internal Server Error", res); } }); }; export const clearFileBuffers = (files) => { for (const file of Object.values(files)) { if (file && file.buffer) { file.buffer = null; } } }; export const generateHash = (levelId, filename, bufferLength) => { return crypto .createHash("md5") .update(levelId + filename + bufferLength) .digest("hex"); }; export const saveFileToDisk = (file, type, levelId, exerciseId) => { const ext = path.extname(file.originalname); const hash = generateHash(levelId, file.originalname, file.buffer.length); const filename = `${type}-${exerciseId}-${hash}${ext}`; let folderPath; switch (type) { case "AUDIO": folderPath = path.join("media/uploads/exercise/audio"); break; case "IMAGE": folderPath = path.join("media/uploads/exercise/image"); break; default: folderPath = path.join("media/uploads/exercise"); } if (!fs.existsSync(folderPath)) { fs.mkdirSync(folderPath, { recursive: true }); } const filepath = path.join(folderPath, filename); fs.writeFileSync(filepath, file.buffer); return filename; }; export default handleUploadSingleExercise;