/** * ⚠️ ⚠️ ⚠️ ENDPOINT DE DEBUG - TEMPORAL ⚠️ ⚠️ ⚠️ * * POST /api/debug/import-database * * IMPORTA UN BACKUP SQL COMPLETO (reemplaza todo lo existente) * * ⚠️ NO ELIMINAR SIN CONSULTAR A DARIO/DRAGANEL/NUCLEO000 ⚠️ * * Este endpoint fue creado para desarrollo y debugging. * Antes de eliminarlo, preguntar si todavía es necesario. */ import { exec } from 'child_process' import { promisify } from 'util' import { writeFile, unlink } from 'fs/promises' import { join } from 'path' const execAsync = promisify(exec) export default defineEventHandler(async (event) => { let tempFilePath: string | null = null try { console.log('📥 IMPORT DATABASE - Importando backup SQL...') // Leer el archivo del request const formData = await readMultipartFormData(event) if (!formData || formData.length === 0) { throw createError({ statusCode: 400, statusMessage: 'No se recibió ningún archivo', data: { message: 'Debes enviar un archivo .sql en el campo "file"' }, }) } const fileData = formData.find(item => item.name === 'file') if (!fileData) { throw createError({ statusCode: 400, statusMessage: 'Campo "file" no encontrado', data: { message: 'El archivo debe enviarse en el campo "file"' }, }) } const sqlContent = fileData.data.toString('utf-8') const fileSize = (sqlContent.length / 1024).toFixed(2) console.log(` - Archivo recibido: ${fileData.filename || 'sin nombre'}`) console.log(` - Tamaño: ${fileSize} KB`) if (!sqlContent.trim()) { throw createError({ statusCode: 400, statusMessage: 'Archivo vacío', data: { message: 'El archivo SQL está vacío' }, }) } // Guardar el archivo temporalmente const timestamp = Date.now() tempFilePath = join('/tmp', `import-${timestamp}.sql`) await writeFile(tempFilePath, sqlContent, 'utf-8') console.log(` - Archivo guardado temporalmente en: ${tempFilePath}`) // Obtener credenciales de la base de datos const config = useRuntimeConfig() let host: string let port: string let database: string let user: string let password: string if (config.postgresUrl) { // Parsear la URL de conexión const url = new URL(config.postgresUrl) host = url.hostname port = url.port || '5432' database = url.pathname.slice(1) user = url.username password = url.password } else { // Fallback a variables de entorno const defaultHost = process.env.APP_NAME ? `${process.env.APP_NAME}-postgres` : 'postgres' host = process.env.POSTGRES_HOST || defaultHost port = process.env.POSTGRES_PORT || '5432' database = process.env.POSTGRES_DB || 'seguidor_lotes' user = process.env.POSTGRES_USER || 'seguidor' password = process.env.POSTGRES_PASSWORD || 'seguidor_password' } console.log(` - Host: ${host}`) console.log(` - Puerto: ${port}`) console.log(` - Base de datos: ${database}`) console.log(` - Usuario: ${user}`) // Ejecutar psql para importar el backup console.log(' - Ejecutando psql para importar el backup...') console.log(' - ADVERTENCIA: Esto eliminará y recreará todas las tablas') const command = `PGPASSWORD="${password}" psql -h ${host} -p ${port} -U ${user} -d ${database} -f ${tempFilePath}` const { stdout, stderr } = await execAsync(command, { maxBuffer: 50 * 1024 * 1024, // 50MB buffer }) // psql envía mensajes normales a stderr, solo preocuparse si hay errores reales if (stderr && stderr.includes('ERROR')) { console.error('⚠️ Errores durante la importación:', stderr) throw new Error(`Error ejecutando psql: ${stderr}`) } if (stderr && !stderr.includes('ERROR')) { console.log(' - Mensajes de psql:', stderr) } console.log('✅ Backup importado exitosamente') return { success: true, message: 'Backup importado exitosamente. La base de datos ha sido restaurada.', file_size: fileSize, filename: fileData.filename || 'sin nombre', } } catch (error: any) { console.error('❌ Error importando backup:', error) // Si el error es porque psql no está disponible if (error.message?.includes('psql') && error.message?.includes('not found')) { throw createError({ statusCode: 500, statusMessage: 'psql no está disponible', data: { message: 'El comando psql no está disponible en el servidor. Asegúrate de que PostgreSQL client tools estén instalados.', }, }) } // Si el error ya es un createError, reusarlo if (error.statusCode) { throw error } throw createError({ statusCode: 500, statusMessage: 'Error importando backup', data: { message: error.message }, }) } finally { // Limpiar el archivo temporal if (tempFilePath) { try { await unlink(tempFilePath) console.log(` - Archivo temporal eliminado: ${tempFilePath}`) } catch (unlinkError) { console.warn('⚠️ No se pudo eliminar el archivo temporal:', unlinkError) } } } })