forked from UKSOURCE/cms.hailearning.edu.vn
198 lines
6.0 KiB
JavaScript
198 lines
6.0 KiB
JavaScript
const multer = require('multer');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const sharp = require('sharp');
|
|
|
|
// Cấu hình storage cho multer
|
|
const storage = multer.diskStorage({
|
|
destination: function (req, file, cb) {
|
|
try {
|
|
// Lấy loại ảnh từ request fields
|
|
const imageType = req.query.imageType || 'general';
|
|
|
|
// Tạo đường dẫn đến thư mục lưu trữ
|
|
const uploadPath = path.join(__dirname, '../public/uploads', imageType);
|
|
|
|
console.log('Creating upload directory:', uploadPath);
|
|
|
|
// Kiểm tra và tạo thư mục nếu chưa tồn tại
|
|
if (!fs.existsSync(uploadPath)) {
|
|
fs.mkdirSync(uploadPath, { recursive: true });
|
|
console.log('Directory created successfully');
|
|
}
|
|
|
|
cb(null, uploadPath);
|
|
} catch (error) {
|
|
console.error('Error creating directory:', error);
|
|
cb(error);
|
|
}
|
|
},
|
|
filename: function (req, file, cb) {
|
|
try {
|
|
const imageType = req.query.imageType || 'general';
|
|
const uploadPath = path.join(__dirname, '../public/uploads', imageType);
|
|
|
|
// Lấy tên file gốc (sanitize để tránh ký tự đặc biệt)
|
|
const originalName = file.originalname.replace(/[^a-zA-Z0-9.-]/g, '_');
|
|
const fullPath = path.join(uploadPath, originalName);
|
|
|
|
// Kiểm tra nếu file đã tồn tại
|
|
if (fs.existsSync(fullPath)) {
|
|
console.log('File already exists, reusing:', originalName);
|
|
// Đánh dấu là file đã tồn tại
|
|
req.fileAlreadyExists = true;
|
|
req.existingFileName = originalName;
|
|
cb(null, originalName);
|
|
} else {
|
|
// File chưa tồn tại, tạo tên mới
|
|
console.log('Creating new file:', originalName);
|
|
cb(null, originalName);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in filename function:', error);
|
|
// Fallback: tạo tên unique nếu có lỗi
|
|
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
|
const ext = path.extname(file.originalname);
|
|
cb(null, file.fieldname + '-' + uniqueSuffix + ext);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Lọc file chỉ cho phép ảnh
|
|
const fileFilter = (req, file, cb) => {
|
|
const allowedTypes = /jpeg|jpg|png|gif|webp|svg/;
|
|
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
|
|
const mimetype = allowedTypes.test(file.mimetype);
|
|
|
|
if (extname && mimetype) {
|
|
return cb(null, true);
|
|
} else {
|
|
cb(new Error('Only image files are allowed!'));
|
|
}
|
|
};
|
|
|
|
// Cấu hình upload
|
|
const upload = multer({
|
|
storage: storage,
|
|
limits: { fileSize: 50 * 1024 * 1024 }, // Giới hạn 50MB
|
|
fileFilter: fileFilter
|
|
});
|
|
|
|
// Cấu hình storage cho video
|
|
const videoStorage = multer.diskStorage({
|
|
destination: function (req, file, cb) {
|
|
// Tạo đường dẫn đến thư mục lưu trữ video
|
|
const uploadPath = path.join(__dirname, '../public/uploads/videos');
|
|
|
|
// Kiểm tra và tạo thư mục nếu chưa tồn tại
|
|
if (!fs.existsSync(uploadPath)) {
|
|
fs.mkdirSync(uploadPath, { recursive: true });
|
|
}
|
|
|
|
cb(null, uploadPath);
|
|
},
|
|
filename: function (req, file, cb) {
|
|
// Tạo tên file duy nhất bằng cách thêm timestamp
|
|
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
|
const ext = path.extname(file.originalname);
|
|
cb(null, 'video-' + uniqueSuffix + ext);
|
|
}
|
|
});
|
|
|
|
// Lọc file chỉ cho phép video
|
|
const videoFileFilter = (req, file, cb) => {
|
|
const allowedTypes = /mp4|webm/;
|
|
const mimetype = allowedTypes.test(file.mimetype);
|
|
|
|
if (mimetype) {
|
|
return cb(null, true);
|
|
} else {
|
|
cb(new Error('Only mp4 and webm video files are allowed!'));
|
|
}
|
|
};
|
|
|
|
// Cấu hình upload video
|
|
const uploadVideo = multer({
|
|
storage: videoStorage,
|
|
limits: { fileSize: 300 * 1024 * 1024 }, // Giới hạn 300MB cho video
|
|
fileFilter: videoFileFilter
|
|
});
|
|
|
|
// Middleware để convert ảnh sau khi multer lưu xong
|
|
|
|
async function convertToWebp(req, res, next) {
|
|
if (!req.file) return next();
|
|
console.log('🔄 Converting image to webp format...');
|
|
console.log('Original file:', req.file.path);
|
|
|
|
try {
|
|
const filePath = req.file.path;
|
|
const webpPath = filePath.replace(path.extname(filePath), '.webp');
|
|
|
|
console.log('Converting to:', webpPath);
|
|
|
|
await sharp(filePath)
|
|
.webp({ quality: 80 })
|
|
.toFile(webpPath);
|
|
|
|
// Xóa file gốc sau khi convert thành công
|
|
if (fs.existsSync(filePath)) {
|
|
fs.unlinkSync(filePath);
|
|
}
|
|
|
|
// Cập nhật thông tin file
|
|
req.file.filename = path.basename(webpPath);
|
|
req.file.path = webpPath;
|
|
|
|
console.log('Image converted successfully');
|
|
next();
|
|
} catch (err) {
|
|
console.error('Error converting image:', err);
|
|
console.error('Error details:', err.message);
|
|
// Nếu convert thất bại, vẫn tiếp tục với file gốc
|
|
next();
|
|
}
|
|
}
|
|
|
|
|
|
// Storage cho degree images — lưu ngoài public/ để không serve trực tiếp
|
|
const degreeStorage = multer.diskStorage({
|
|
destination: function (req, file, cb) {
|
|
const uploadPath = path.join(__dirname, '../private/uploads/degree');
|
|
if (!fs.existsSync(uploadPath)) {
|
|
fs.mkdirSync(uploadPath, { recursive: true });
|
|
}
|
|
cb(null, uploadPath);
|
|
},
|
|
filename: function (req, file, cb) {
|
|
const ext = path.extname(file.originalname);
|
|
cb(null, `degree-${Date.now()}-${Math.round(Math.random() * 1e9)}${ext}`);
|
|
}
|
|
});
|
|
|
|
// Lọc file chỉ cho phép ảnh degree
|
|
const degreeFileFilter = (req, file, cb) => {
|
|
const allowedMimes = ['image/jpeg', 'image/png', 'image/webp'];
|
|
if (allowedMimes.includes(file.mimetype)) {
|
|
cb(null, true);
|
|
} else {
|
|
cb(new Error('Only image/jpeg, image/png, image/webp files are allowed!'));
|
|
}
|
|
};
|
|
|
|
// Cấu hình upload degree
|
|
const uploadDegree = multer({
|
|
storage: degreeStorage,
|
|
limits: { fileSize: 5 * 1024 * 1024 }, // 5MB per file
|
|
fileFilter: degreeFileFilter
|
|
}).fields([
|
|
{ name: 'degree_image', maxCount: 1 },
|
|
{ name: 'certificate_image', maxCount: 1 }
|
|
]);
|
|
|
|
module.exports = {
|
|
upload,
|
|
uploadVideo,
|
|
convertToWebp,
|
|
uploadDegree
|
|
}; |