Files
sena_db_api_layer/controllers/uploadController.js
silverpro89 fa5c293a7e
All checks were successful
Deploy to Production / deploy (push) Successful in 21s
update router getType
2026-01-28 18:59:06 +07:00

277 lines
7.3 KiB
JavaScript

const multer = require('multer');
const path = require('path');
const fs = require('fs');
/**
* Upload Controller - Quản lý upload file
*/
class UploadController {
constructor() {
// Danh sách các extension cho từng loại file
this.imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg', '.ico'];
this.audioExtensions = ['.mp3', '.wav', '.ogg', '.m4a', '.aac', '.flac', '.wma'];
this.videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', '.webm'];
// Tạo các thư mục nếu chưa tồn tại
this.ensureDirectories();
// Cấu hình multer storage
this.storage = multer.diskStorage({
destination: (req, file, cb) => {
const fileExt = path.extname(file.originalname).toLowerCase();
let uploadPath = 'public/files';
if (this.imageExtensions.includes(fileExt)) {
uploadPath = 'public/images';
} else if (this.audioExtensions.includes(fileExt) || this.videoExtensions.includes(fileExt)) {
uploadPath = 'public/media';
}
cb(null, uploadPath);
},
filename: (req, file, cb) => {
// Tạo tên file unique: timestamp-random-originalname
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
const ext = path.extname(file.originalname);
const nameWithoutExt = path.basename(file.originalname, ext);
const sanitizedName = nameWithoutExt.replace(/[^a-zA-Z0-9]/g, '_');
cb(null, `${sanitizedName}-${uniqueSuffix}${ext}`);
}
});
// Cấu hình multer với giới hạn kích thước
this.upload = multer({
storage: this.storage,
limits: {
fileSize: 50 * 1024 * 1024, // 50MB max file size
},
fileFilter: (req, file, cb) => {
// Cho phép tất cả các loại file
cb(null, true);
}
});
}
/**
* Đảm bảo các thư mục upload tồn tại
*/
ensureDirectories() {
const directories = [
'public/images',
'public/media',
'public/files'
];
directories.forEach(dir => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
});
}
/**
* Upload single file
*/
uploadSingle(req, res, next) {
const uploadHandler = this.upload.single('file');
uploadHandler(req, res, (err) => {
if (err instanceof multer.MulterError) {
return res.status(400).json({
success: false,
message: 'Upload error',
error: err.message,
});
} else if (err) {
return res.status(500).json({
success: false,
message: 'Server error during upload',
error: err.message,
});
}
if (!req.file) {
return res.status(400).json({
success: false,
message: 'No file uploaded',
});
}
// Xác định loại file
const fileExt = path.extname(req.file.originalname).toLowerCase();
let fileType = 'file';
if (this.imageExtensions.includes(fileExt)) {
fileType = 'image';
} else if (this.audioExtensions.includes(fileExt)) {
fileType = 'audio';
} else if (this.videoExtensions.includes(fileExt)) {
fileType = 'video';
}
// Tạo URL truy cập file
const fileUrl = `/${req.file.path.replace(/\\/g, '/')}`;
res.status(201).json({
success: true,
message: 'File uploaded successfully',
data: {
filename: req.file.filename,
originalname: req.file.originalname,
mimetype: req.file.mimetype,
size: req.file.size,
type: fileType,
path: req.file.path,
url: fileUrl,
},
});
});
}
/**
* Upload multiple files
*/
uploadMultiple(req, res, next) {
const uploadHandler = this.upload.array('files', 10); // Max 10 files
uploadHandler(req, res, (err) => {
if (err instanceof multer.MulterError) {
return res.status(400).json({
success: false,
message: 'Upload error',
error: err.message,
});
} else if (err) {
return res.status(500).json({
success: false,
message: 'Server error during upload',
error: err.message,
});
}
if (!req.files || req.files.length === 0) {
return res.status(400).json({
success: false,
message: 'No files uploaded',
});
}
const uploadedFiles = req.files.map(file => {
const fileExt = path.extname(file.originalname).toLowerCase();
let fileType = 'file';
if (this.imageExtensions.includes(fileExt)) {
fileType = 'image';
} else if (this.audioExtensions.includes(fileExt)) {
fileType = 'audio';
} else if (this.videoExtensions.includes(fileExt)) {
fileType = 'video';
}
const fileUrl = `/${file.path.replace(/\\/g, '/')}`;
return {
filename: file.filename,
originalname: file.originalname,
mimetype: file.mimetype,
size: file.size,
type: fileType,
path: file.path,
url: fileUrl,
};
});
res.status(201).json({
success: true,
message: `${uploadedFiles.length} files uploaded successfully`,
data: uploadedFiles,
});
});
}
/**
* Delete file
*/
async deleteFile(req, res, next) {
try {
const { filepath } = req.body;
if (!filepath) {
return res.status(400).json({
success: false,
message: 'Filepath is required',
});
}
// Kiểm tra file có tồn tại không
if (!fs.existsSync(filepath)) {
return res.status(404).json({
success: false,
message: 'File not found',
});
}
// Xóa file
fs.unlinkSync(filepath);
res.json({
success: true,
message: 'File deleted successfully',
});
} catch (error) {
next(error);
}
}
/**
* Get file info
*/
async getFileInfo(req, res, next) {
try {
const { filepath } = req.query;
if (!filepath) {
return res.status(400).json({
success: false,
message: 'Filepath is required',
});
}
// Kiểm tra file có tồn tại không
if (!fs.existsSync(filepath)) {
return res.status(404).json({
success: false,
message: 'File not found',
});
}
const stats = fs.statSync(filepath);
const fileExt = path.extname(filepath).toLowerCase();
let fileType = 'file';
if (this.imageExtensions.includes(fileExt)) {
fileType = 'image';
} else if (this.audioExtensions.includes(fileExt)) {
fileType = 'audio';
} else if (this.videoExtensions.includes(fileExt)) {
fileType = 'video';
}
res.json({
success: true,
data: {
path: filepath,
size: stats.size,
type: fileType,
created: stats.birthtime,
modified: stats.mtime,
},
});
} catch (error) {
next(error);
}
}
}
module.exports = new UploadController();