diff --git a/nuxt4/app/app.vue b/nuxt4/app/app.vue index e031da5..32e8b34 100644 --- a/nuxt4/app/app.vue +++ b/nuxt4/app/app.vue @@ -87,6 +87,21 @@ > 💾 EXPORTAR BACKUP + + 📥 IMPORTAR BACKUP + +

Resultados en consola (F12). Recarga la página después de usar estos botones. @@ -459,6 +474,8 @@ const resettingDB = ref(false) const seedingDB = ref(false) const clearingData = ref(false) const exportingDB = ref(false) +const importingDB = ref(false) +const fileInputRef = ref(null) const resetDatabase = async () => { if (!confirm('⚠️ ADVERTENCIA: Esto BORRARÁ TODOS LOS DATOS de la base de datos.\n\n¿Estás seguro de continuar?')) { @@ -574,6 +591,61 @@ const exportDatabase = async () => { exportingDB.value = false } } + +const triggerFileInput = () => { + fileInputRef.value?.click() +} + +const importDatabase = async (event: Event) => { + const input = event.target as HTMLInputElement + const file = input.files?.[0] + + if (!file) { + return + } + + if (!file.name.endsWith('.sql')) { + alert('⚠️ Por favor selecciona un archivo .sql') + input.value = '' + return + } + + if (!confirm('⚠️ ADVERTENCIA: Esto REEMPLAZARÁ TODA LA BASE DE DATOS con el contenido del backup.\n\nSe eliminará todo lo existente y se cargará el backup.\n\n¿Estás seguro de continuar?')) { + input.value = '' + return + } + + console.log('📥 === IMPORTANDO BACKUP DE BASE DE DATOS ===') + console.log(` - Archivo: ${file.name}`) + console.log(` - Tamaño: ${(file.size / 1024).toFixed(2)} KB`) + importingDB.value = true + + try { + const formData = new FormData() + formData.append('file', file) + + const response = await fetch('/api/debug/import-database', { + method: 'POST', + body: formData, + }) + + const data = await response.json() + console.log('Status:', response.status) + console.log('Respuesta:', data) + + if (data.success) { + alert('✅ Backup importado exitosamente.\n\nLa base de datos ha sido restaurada.\n\nRecarga la página para ver los cambios.') + } else { + throw new Error(data.message || 'Error desconocido') + } + } catch (error: any) { + console.error('❌ Error:', error) + alert(`❌ Error importando backup: ${error.message || 'Ver consola para más detalles'}`) + } finally { + importingDB.value = false + input.value = '' // Limpiar el input + } +} // ⚠️⚠️⚠️ FIN FUNCIONES DE DEBUG ⚠️⚠️⚠️ // Funciones de prueba de API diff --git a/nuxt4/server/api/debug/import-database.post.ts b/nuxt4/server/api/debug/import-database.post.ts new file mode 100644 index 0000000..fc35c86 --- /dev/null +++ b/nuxt4/server/api/debug/import-database.post.ts @@ -0,0 +1,97 @@ +/** + * ⚠️ ⚠️ ⚠️ 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 { getClient } from '../../utils/db' + +export default defineEventHandler(async (event) => { + 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' }, + }) + } + + const client = await getClient() + + try { + await client.query('BEGIN') + + console.log(' - Ejecutando SQL del backup...') + console.log(' - ADVERTENCIA: Esto eliminará y recreará todas las tablas') + + // Ejecutar el SQL del backup + // Los backups de pg_dump con --clean --if-exists ya incluyen los DROP necesarios + await client.query(sqlContent) + + await client.query('COMMIT') + + 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) { + await client.query('ROLLBACK') + throw error + } finally { + client.release() + } + } catch (error: any) { + console.error('❌ Error importando backup:', error) + + // 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 }, + }) + } +})