172 lines
4.5 KiB
JavaScript
172 lines
4.5 KiB
JavaScript
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;
|