// FLUJOS_APP.js ubicado en /var/www/flujos/FLUJOS/BACK_BACK/ require('dotenv').config(); // Cargar variables de entorno desde .env const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const helmet = require('helmet'); const { MongoClient } = require('mongodb'); const app = express(); const port = process.env.PORT || 3000; // Configurar Helmet con CSP personalizado app.use( helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: [ "'self'", "'unsafe-inline'", 'https://unpkg.com', 'https://cdnjs.cloudflare.com', 'https://fonts.googleapis.com', 'https://fonts.gstatic.com', ], styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'], imgSrc: ["'self'", 'data:'], connectSrc: ["'self'", 'ws://localhost:3000'], fontSrc: ["'self'", 'https://fonts.gstatic.com'], }, }) ); app.use(bodyParser.json()); // **Definir primero las rutas de la API** app.get('/api/data', async (req, res) => { console.log('Solicitud recibida en /api/data'); try { // Asegurarse de que la conexión a la base de datos está establecida if (!db) { res.status(500).json({ error: 'No hay conexión a la base de datos' }); return; } // Acceder a las colecciones necesarias const wikipediaCollection = db.collection('wikipedia'); const noticiasCollection = db.collection('noticias'); const torrentsCollection = db.collection('torrents'); const comparacionesCollection = db.collection('comparaciones'); // Obtener los parámetros de consulta del cliente const { tema, subtematica, palabraClave, fechaInicio, fechaFin, nodos, complejidad } = req.query; console.log('Parámetros de consulta:', req.query); // Validar que el parámetro 'tema' esté presente if (!tema) { res.status(400).json({ error: 'El parámetro "tema" es obligatorio' }); return; } // Construir la consulta para obtener los nodos (noticias, wikipedia y torrents) let nodesQuery = { tema: tema, // Usar el tema proporcionado }; if (subtematica) nodesQuery.subtema = subtematica; if (palabraClave) nodesQuery.texto = { $regex: palabraClave, $options: 'i' }; if (fechaInicio && fechaFin) { nodesQuery.fecha = { $gte: new Date(fechaInicio), $lte: new Date(fechaFin), }; } console.log('Consulta para nodos:', nodesQuery); // Obtener el límite de nodos (con un máximo para evitar sobrecarga) const nodosLimit = Math.min(parseInt(nodos) || 100, 500); // Ejecutar la consulta y obtener los resultados de las colecciones console.log('Ejecutando consulta para nodos en colecciones...'); const [wikipediaNodes, noticiasNodes, torrentsNodes] = await Promise.all([ wikipediaCollection.find(nodesQuery).limit(nodosLimit).toArray(), noticiasCollection.find(nodesQuery).limit(nodosLimit).toArray(), torrentsCollection.find(nodesQuery).limit(nodosLimit).toArray(), ]); console.log('Nodos de Wikipedia obtenidos:', wikipediaNodes.length); console.log('Nodos de Noticias obtenidos:', noticiasNodes.length); console.log('Nodos de Torrents obtenidos:', torrentsNodes.length); // Combinar los nodos de las colecciones const nodes = [...wikipediaNodes, ...noticiasNodes, ...torrentsNodes]; console.log('Total de nodos combinados:', nodes.length); // Utilizar los nombres de archivo exactos como IDs de los nodos const formattedNodes = nodes.map((result) => ({ id: result.archivo.trim(), // Utilizar el nombre de archivo exacto sin normalizar group: result.subtema || 'sin subtema', tema: result.tema || 'sin tema', content: result.texto || '', fecha: result.fecha || '', })); // Obtener los IDs de los nodos const nodeIds = formattedNodes.map(node => node.id); console.log('IDs de nodos:', nodeIds); // Leer el parámetro 'complejidad' de la query (que en tu front envías como % de similitud) const porcentajeSimilitudMin = parseFloat(complejidad) || 0; console.log('Porcentaje de similitud mínimo (desde complejidad):', porcentajeSimilitudMin); // Construir la consulta para obtener los enlaces relacionados con los nodos obtenidos const linksQuery = { porcentaje_similitud: { $gte: porcentajeSimilitudMin }, noticia1: { $in: nodeIds }, noticia2: { $in: nodeIds }, }; console.log('Consulta para enlaces:', linksQuery); // Ejecutar la consulta y obtener los enlaces console.log('Ejecutando consulta para enlaces...'); const links = await comparacionesCollection.find(linksQuery).toArray(); console.log('Enlaces obtenidos:', links.length); // Formatear los enlaces sin normalizar los IDs const formattedLinks = links.map((result) => ({ source: result.noticia1.trim(), target: result.noticia2.trim(), value: result.porcentaje_similitud, })); // Enviar los datos al cliente en formato JSON res.json({ nodes: formattedNodes, links: formattedLinks }); console.log('Datos enviados al cliente'); } catch (error) { console.error('Error al obtener datos:', error); res.status(500).json({ error: 'Error al obtener datos' }); } }); // **Luego, definir las rutas de las páginas principales** // Rutas para las páginas principales app.get('/', (req, res) => { res.sendFile(path.join(__dirname, '../VISUALIZACION/public/index.html')); }); app.get('/climate.html', (req, res) => { res.sendFile(path.join(__dirname, '../VISUALIZACION/public/climate.html')); }); app.get('/glob-war.html', (req, res) => { res.sendFile(path.join(__dirname, '../VISUALIZACION/public/glob-war.html')); }); app.get('/popl-up.html', (req, res) => { res.sendFile(path.join(__dirname, '../VISUALIZACION/public/popl-up.html')); }); app.get('/int-sec.html', (req, res) => { res.sendFile(path.join(__dirname, '../VISUALIZACION/public/int-sec.html')); }); app.get('/eco-corp.html', (req, res) => { res.sendFile(path.join(__dirname, '../VISUALIZACION/public/eco-corp.html')); }); // **Después, configurar el middleware de archivos estáticos** app.use(express.static(path.join(__dirname, '../VISUALIZACION/public'))); // Conexión a MongoDB usando variables de entorno const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost:27017'; const dbName = process.env.DB_NAME || 'FLUJOS_DATOS'; let db; // Variable para almacenar la conexión a la base de datos // Función para conectar a MongoDB async function connectToMongoDB() { try { const mongoClient = new MongoClient(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true, }); await mongoClient.connect(); db = mongoClient.db(dbName); console.log('Conectado a MongoDB'); } catch (error) { console.error('Error al conectar a MongoDB:', error); process.exit(1); // Salir de la aplicación si no se puede conectar } } // Llamar a la función para conectar a MongoDB connectToMongoDB(); // Iniciar el servidor escuchando en todas las interfaces app.listen(port, '0.0.0.0', () => { console.log(`La aplicación está escuchando en http://localhost:${port}`); }); // Manejar el cierre de la aplicación process.on('SIGINT', async () => { if (db) { await db.close(); console.log('Conexión a MongoDB cerrada'); } process.exit(0); });