import multer from "multer"; import crypto from "crypto"; import path from "path"; import fs from "fs"; import response from "../response.js"; // Setup memory storage for Multer const memoryStorage = multer.memoryStorage(); // Filter untuk membatasi tipe file dan ukuran file 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": 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); } }; // Set up Multer untuk menangani upload const upload = multer({ storage: memoryStorage, fileFilter, limits: { fileSize: 100 * 1024 * 1024, // Total file size limit if needed }, }).fields([ { name: "video", maxCount: 1 }, { name: "audio", maxCount: 1 }, { name: "image", maxCount: 1 }, ]); // Middleware untuk menangani upload dan pengecekan file size const handleUpload = (req, res, next) => { upload(req, res, (err) => { if (err) { return response(400, null, err.message, res); } 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; try { let validFiles = true; let errorMessages = []; // Validate file sizes if (video && video.size > 30 * 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; 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) { // Attach files to the request object for further processing req.filesToSave = { video, audio, image }; next(); } else { // Clear file buffers and return error response with specific messages clearFileBuffers({ video, 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); } }); }; // Function to clear file buffers export const clearFileBuffers = (files) => { for (const file of Object.values(files)) { if (file && file.buffer) { file.buffer = null; } } }; export const generateHash = (subjectId, filename, bufferLength) => { return crypto .createHash("md5") .update(subjectId + filename + bufferLength) .digest("hex"); }; // Function to save files to disk export const saveFileToDisk = (file, type, title, topicId, subjectId) => { const formattedTitle = title.replace(/\s+/g, '').toLowerCase(); const ext = path.extname(file.originalname); const hash = generateHash(subjectId, file.originalname, file.buffer.length); const filename = `${topicId}-${formattedTitle}-${type}-${hash}${ext}`; let folderPath; switch (type) { case "video": folderPath = path.join("public/uploads/level/video"); break; 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 handleUpload;