feat: Agregar modulo de Sistema (mongosh, logs, export/import)

This commit is contained in:
2026-08-12 03:17:28 +00:00
parent e038c25e9e
commit 205c8f1c7c
6 changed files with 450 additions and 3 deletions
+119 -1
View File
@@ -17,9 +17,43 @@ import { initDb,
getAllIndicaciones, createIndicacion, updateIndicacion, deleteIndicacion,
getAllMovimientosIndicaciones, createMovimientoIndicacion,
getAllPendientes, createPendiente, updatePendiente, deletePendiente,
getValue, setValue
getValue, setValue,
getDb, exportAllData, importAllData
} from './db-mongodb.js';
// Capture live logs in-memory
const logBuffer = [];
const originalLog = console.log;
const originalError = console.error;
const originalWarn = console.warn;
function addLog(type, args) {
const message = args.map(arg => {
if (typeof arg === 'object') {
try { return JSON.stringify(arg); } catch { return String(arg); }
}
return String(arg);
}).join(' ');
const logEntry = `[${new Date().toISOString()}] [${type}] ${message}`;
logBuffer.push(logEntry);
if (logBuffer.length > 500) {
logBuffer.shift();
}
}
console.log = (...args) => {
addLog('INFO', args);
originalLog.apply(console, args);
};
console.error = (...args) => {
addLog('ERROR', args);
originalError.apply(console, args);
};
console.warn = (...args) => {
addLog('WARN', args);
originalWarn.apply(console, args);
};
const app = express();
app.use(cors({
origin: true,
@@ -760,6 +794,90 @@ app.put('/api/auth/update-email', async (req, res) => {
}
});
// ========== ADMIN SYSTEM ENDPOINTS ==========
app.post('/api/admin/mongosh', async (req, res) => {
try {
const { command } = req.body;
if (!command) {
return res.status(400).json({ error: 'Comando requerido' });
}
const dbInstance = getDb();
if (!dbInstance) {
return res.json({ result: 'Advertencia: MongoDB no está conectado. Utilizando store en memoria. Las consultas de mongosh no están disponibles.', isMemStore: true });
}
const dbProxy = new Proxy(dbInstance, {
get(target, prop) {
if (typeof target[prop] !== 'undefined') {
if (typeof target[prop] === 'function') {
return target[prop].bind(target);
}
return target[prop];
}
return target.collection(prop);
}
});
const { ObjectId } = await import('mongodb');
const evalFn = new Function('db', 'ObjectId', `
return (async () => {
${command.trim().includes('return') || command.trim().startsWith('{') || command.trim().includes(';') ? command : 'return (' + command + ')'}
})();
`);
const result = await evalFn(dbProxy, ObjectId);
res.json({ result });
} catch (err) {
res.status(400).json({ error: err.message || String(err) });
}
});
app.get('/api/admin/db/export', async (req, res) => {
try {
const dump = await exportAllData();
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Disposition', 'attachment; filename=hospital_backup.json');
res.json(dump);
} catch (err) {
res.status(500).json({ error: 'Error al exportar base de datos: ' + err.message });
}
});
app.post('/api/admin/db/import', async (req, res) => {
try {
const dump = req.body;
if (!dump || typeof dump !== 'object') {
return res.status(400).json({ error: 'Formato de importación inválido' });
}
await importAllData(dump);
res.json({ ok: true });
} catch (err) {
res.status(500).json({ error: 'Error al importar base de datos: ' + err.message });
}
});
app.get('/api/admin/logs', async (req, res) => {
try {
let fileLogs = '';
try {
const fs = await import('fs/promises');
fileLogs = await fs.readFile('server_log.txt', 'utf8');
} catch {
// ignore
}
const memoryLogs = logBuffer.join('\n');
const combined = [fileLogs, '\n--- LOGS DE LA SESION EN VIVO ---', memoryLogs].filter(Boolean).join('\n');
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.send(combined);
} catch (err) {
res.status(500).send('Error al leer logs: ' + err.message);
}
});
// Initialize DB and start server
const PORT = process.env.PORT || 4000;
const HOST = process.env.HOST || '0.0.0.0';