ABIANAPP_NODE_PRODUCCION/src/middleware/profilePhotoUpload.js

85 lines
2.6 KiB
JavaScript

const crypto = require('crypto');
const fs = require('fs');
const multer = require('multer');
const path = require('path');
const MAX_PROFILE_PHOTO_SIZE_BYTES = 5 * 1024 * 1024;
const PROFILE_UPLOADS_DIR = path.resolve(__dirname, '..', '..', 'uploads', 'profile');
const ALLOWED_MIME_TYPES = new Set(['image/jpeg', 'image/png']);
const ensureProfileUploadsDir = () => {
fs.mkdirSync(PROFILE_UPLOADS_DIR, { recursive: true });
};
const sanitizeFileBaseName = (originalName) => {
const baseName = path.basename(originalName || 'profile_photo', path.extname(originalName || ''));
const sanitized = baseName
.replace(/[^a-zA-Z0-9_-]/g, '_')
.replace(/_+/g, '_')
.replace(/^_+|_+$/g, '')
.slice(0, 40);
return sanitized || 'profile_photo';
};
const getExtensionFromMimeType = (mimeType) => (mimeType === 'image/png' ? '.png' : '.jpg');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
try {
ensureProfileUploadsDir();
cb(null, PROFILE_UPLOADS_DIR);
} catch (error) {
cb(error);
}
},
filename: (req, file, cb) => {
const safeBaseName = sanitizeFileBaseName(file.originalname);
const uniqueSuffix = `${Date.now()}_${crypto.randomBytes(6).toString('hex')}`;
const extension = getExtensionFromMimeType(file.mimetype);
cb(null, `${safeBaseName}_${uniqueSuffix}${extension}`);
}
});
const internalUpload = multer({
storage,
limits: {
fileSize: MAX_PROFILE_PHOTO_SIZE_BYTES,
files: 1
},
fileFilter: (req, file, cb) => {
if (!ALLOWED_MIME_TYPES.has(file.mimetype)) {
return cb(new Error('INVALID_FILE_TYPE'));
}
cb(null, true);
}
});
const uploadProfilePhoto = (req, res, next) => {
internalUpload.single('foto_perfil')(req, res, (error) => {
if (!error) {
return next();
}
if (error instanceof multer.MulterError) {
if (error.code === 'LIMIT_FILE_SIZE') {
return res.status(400).json({ error: 'Archivo demasiado grande. Maximo 5MB.' });
}
return res.status(400).json({ error: 'Archivo invalido.' });
}
if (error.message === 'INVALID_FILE_TYPE') {
return res.status(400).json({ error: 'Tipo de archivo invalido. Solo se permite image/jpeg o image/png.' });
}
console.error('Error uploading profile photo:', error);
return res.status(500).json({ error: 'Internal server error' });
});
};
module.exports = {
uploadProfilePhoto
};