85 lines
2.6 KiB
JavaScript
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
|
|
};
|