refactor on components and delete clear, profesional login

This commit is contained in:
Omar Sánchez Pizarro
2026-01-20 18:15:49 +01:00
parent d1a8055727
commit 804efe7663
17 changed files with 831 additions and 516 deletions

View File

@@ -50,7 +50,7 @@ backend/
### Routes (`routes/`)
Cada archivo maneja un conjunto relacionado de endpoints:
- **index.js**: `/api/stats`, `/api/cache`
- **index.js**: `/api/stats`
- **workers.js**: `/api/workers` (GET, PUT)
- **articles.js**: `/api/articles` (GET, search)
- **favorites.js**: `/api/favorites` (GET, POST, DELETE)

View File

@@ -4,15 +4,6 @@ import { basicAuthMiddleware } from '../middlewares/auth.js';
const router = express.Router();
router.delete('/', basicAuthMiddleware, async (req, res) => {
try {
const count = await clearAllArticles();
res.json({ success: true, message: `Todos los artículos eliminados: ${count} artículos borrados`, count });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Obtener artículos notificados (requiere autenticación obligatoria)
router.get('/', basicAuthMiddleware, async (req, res) => {
try {

View File

@@ -1,5 +1,5 @@
import express from 'express';
import { getFavorites, getNotifiedArticles, getDB, getWorkers, clearAllArticles } from '../services/mongodb.js';
import { getFavorites, getNotifiedArticles, getDB, getWorkers } from '../services/mongodb.js';
import { basicAuthMiddleware } from '../middlewares/auth.js';
import { adminAuthMiddleware } from '../middlewares/adminAuth.js';
import { broadcast } from '../services/websocket.js';
@@ -92,75 +92,5 @@ router.get('/stats', basicAuthMiddleware, async (req, res) => {
}
});
// Limpiar toda la caché de MongoDB (requiere autenticación de administrador)
router.delete('/cache', basicAuthMiddleware, adminAuthMiddleware, async (req, res) => {
try {
const db = getDB();
if (!db) {
return res.status(500).json({ error: 'MongoDB no está disponible' });
}
// Eliminar todos los artículos
const count = await clearAllArticles();
// Notificar a los clientes WebSocket
broadcast({
type: 'cache_cleared',
data: { count, timestamp: Date.now() }
});
// También notificar actualización de artículos (ahora está vacío)
broadcast({ type: 'articles_updated', data: [] });
// También actualizar favoritos (debería estar vacío ahora)
const favorites = await getFavorites(null);
broadcast({ type: 'favorites_updated', data: favorites, username: null });
res.json({
success: true,
message: `Todos los artículos eliminados: ${count} artículos borrados`,
count
});
} catch (error) {
console.error('Error limpiando cache de MongoDB:', error);
res.status(500).json({ error: error.message });
}
});
// Endpoint específico para borrar artículos (alias de /cache para claridad)
router.delete('/articles', basicAuthMiddleware, adminAuthMiddleware, async (req, res) => {
try {
const db = getDB();
if (!db) {
return res.status(500).json({ error: 'MongoDB no está disponible' });
}
// Eliminar todos los artículos
const count = await clearAllArticles();
// Notificar a los clientes WebSocket
broadcast({
type: 'articles_cleared',
data: { count, timestamp: Date.now() }
});
// También notificar actualización de artículos (ahora está vacío)
broadcast({ type: 'articles_updated', data: [] });
// También actualizar favoritos (debería estar vacío ahora)
const favorites = await getFavorites(null);
broadcast({ type: 'favorites_updated', data: favorites, username: null });
res.json({
success: true,
message: `Todos los artículos eliminados: ${count} artículos borrados`,
count
});
} catch (error) {
console.error('Error borrando artículos:', error);
res.status(500).json({ error: error.message });
}
});
export default router;

View File

@@ -799,21 +799,6 @@ export async function updateArticleFavorite(platform, id, is_favorite, username)
}
}
export async function clearAllArticles() {
if (!db) {
return 0;
}
try {
const articlesCollection = db.collection('articles');
const result = await articlesCollection.deleteMany({});
return result.deletedCount;
} catch (error) {
console.error('Error limpiando artículos:', error.message);
return 0;
}
}
// Cerrar conexión
export async function closeMongoDB() {
if (mongoClient) {

View File

@@ -1,16 +1,93 @@
import { WebSocketServer } from 'ws';
import { getDB, getSession, getUser, deleteSession as deleteSessionFromDB } from './mongodb.js';
let wss = null;
// Duración de la sesión en milisegundos (24 horas)
const SESSION_DURATION = 24 * 60 * 60 * 1000;
// Inicializar WebSocket Server
export function initWebSocket(server) {
wss = new WebSocketServer({ server, path: '/ws' });
wss.on('connection', (ws) => {
console.log('Cliente WebSocket conectado');
wss.on('connection', async (ws, req) => {
// Extraer token de los query parameters
const url = new URL(req.url, `http://${req.headers.host}`);
const token = url.searchParams.get('token');
if (!token) {
console.log('Intento de conexión WebSocket sin token');
ws.close(1008, 'Token requerido');
return;
}
// Validar token
try {
const db = getDB();
if (!db) {
console.error('MongoDB no disponible para validar WebSocket');
ws.close(1011, 'Servicio no disponible');
return;
}
// Verificar token en MongoDB
const session = await getSession(token);
if (!session) {
console.log('Intento de conexión WebSocket con token inválido');
ws.close(1008, 'Token inválido');
return;
}
// Verificar que la sesión no haya expirado
if (session.expiresAt && new Date(session.expiresAt) < new Date()) {
await deleteSessionFromDB(token);
console.log('Intento de conexión WebSocket con sesión expirada');
ws.close(1008, 'Sesión expirada');
return;
}
// Verificar que el usuario aún existe
const user = await getUser(session.username);
if (!user) {
// Eliminar sesión si el usuario ya no existe
await deleteSessionFromDB(token);
console.log('Intento de conexión WebSocket con usuario inexistente');
ws.close(1008, 'Usuario no encontrado');
return;
}
// Actualizar expiración de la sesión (refresh)
const sessionsCollection = db.collection('sessions');
const newExpiresAt = new Date(Date.now() + SESSION_DURATION);
await sessionsCollection.updateOne(
{ token },
{ $set: { expiresAt: newExpiresAt } }
);
// Autenticación exitosa - almacenar información del usuario en el websocket
ws.user = {
username: session.username,
role: user.role || 'user',
token: token
};
console.log(`Cliente WebSocket conectado: ${session.username} (${user.role || 'user'})`);
} catch (error) {
console.error('Error validando token WebSocket:', error);
ws.close(1011, 'Error de autenticación');
return;
}
ws.on('close', () => {
console.log('Cliente WebSocket desconectado');
if (ws.user) {
console.log(`Cliente WebSocket desconectado: ${ws.user.username}`);
} else {
console.log('Cliente WebSocket desconectado');
}
});
ws.on('error', (error) => {