Primer commit del sistema separado falta mejorar mucho

This commit is contained in:
nickpons666
2025-12-30 01:18:46 -06:00
commit 1679c73e52
2384 changed files with 472342 additions and 0 deletions

322
discord/views/logs/list.php Executable file
View File

@@ -0,0 +1,322 @@
<?php
session_start();
// Habilitar logging para depuración
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../shared/utils/helpers.php';
require_once __DIR__ . '/../../../shared/auth/jwt.php';
require_once __DIR__ . '/../../../shared/database/connection.php';
$userData = JWTAuth::requireAuth();
$db = getDB();
// Paginación
$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
$perPage = 20;
$offset = ($page - 1) * $perPage;
// Filtros
$nivel = isset($_GET['nivel']) ? $_GET['nivel'] : '';
$origen = isset($_GET['origen']) ? $_GET['origen'] : '';
$search = isset($_GET['search']) ? trim($_GET['search']) : '';
// Construir Query
$where = ["1=1"];
$params = [];
if ($nivel) {
$where[] = "nivel = ?";
$params[] = $nivel;
}
if ($origen) {
$where[] = "origen = ?";
$params[] = $origen;
}
if ($search) {
$where[] = "descripcion LIKE ?";
$params[] = "%$search%";
}
$whereClause = implode(" AND ", $where);
// Total para paginación
$stmt = $db->prepare("SELECT COUNT(*) FROM logs_discord WHERE $whereClause");
$stmt->execute($params);
$totalLogs = $stmt->fetchColumn();
$totalPages = ceil($totalLogs / $perPage);
// Obtener logs
$stmt = $db->prepare("
SELECT l.*, u.username
FROM logs_discord l
LEFT JOIN usuarios u ON l.usuario_id = u.id
WHERE $whereClause
ORDER BY l.fecha DESC
LIMIT $perPage OFFSET $offset
");
$stmt->execute($params);
$logs = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="<?php echo $userData->idioma ?? 'es'; ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Logs Discord - Sistema de Bots</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--discord-color: #5865F2;
--discord-dark: #4752C4;
--bg-color: #f0f2f5;
--text-color: #333;
--success: #28a745;
--warning: #ffc107;
--danger: #dc3545;
--info: #17a2b8;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg-color);
min-height: 100vh;
padding: 20px;
}
.header {
background: white;
border-radius: 15px;
padding: 20px 30px;
margin-bottom: 30px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
}
.header h1 { color: var(--discord-color); font-size: 24px; }
.container { max-width: 1200px; margin: 0 auto; }
.card {
background: white;
border-radius: 15px;
padding: 25px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.filters {
display: flex;
gap: 15px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.form-control {
padding: 10px;
border: 2px solid #eee;
border-radius: 8px;
min-width: 150px;
}
.btn {
padding: 10px 20px;
border-radius: 8px;
text-decoration: none;
border: none;
cursor: pointer;
font-weight: 600;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary { background: var(--discord-color); color: white; }
.btn-secondary { background: #6c757d; color: white; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 15px; text-align: left; border-bottom: 1px solid #eee; }
th { background: #f8f9fa; color: #555; font-weight: 600; }
.badge {
padding: 5px 10px;
border-radius: 15px;
font-size: 12px;
font-weight: 600;
color: white;
}
.badge-info { background: var(--info); }
.badge-warning { background: var(--warning); color: #333; }
.badge-error { background: var(--danger); }
.pagination {
display: flex;
justify-content: center;
gap: 10px;
margin-top: 20px;
}
.pagination a {
padding: 8px 12px;
background: white;
border: 1px solid #ddd;
border-radius: 5px;
text-decoration: none;
color: var(--discord-color);
}
.pagination a.active {
background: var(--discord-color);
color: white;
border-color: var(--discord-color);
}
/* Modal JSON */
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); }
.modal-content { background: white; margin: 10% auto; padding: 25px; width: 80%; max-width: 800px; border-radius: 15px; position: relative; max-height: 80vh; overflow-y: auto; }
.close-modal { position: absolute; top: 15px; right: 20px; font-size: 24px; cursor: pointer; color: #aaa; }
pre {
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
font-family: monospace;
}
</style>
</head>
<body>
<div class="header">
<h1><i class="fas fa-list-alt"></i> Logs del Sistema</h1>
<a href="/discord/dashboard_discord.php" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Volver
</a>
</div>
<div class="container">
<div class="card">
<form class="filters" method="GET">
<input type="text" name="search" class="form-control" placeholder="Buscar en descripción..." value="<?php echo htmlspecialchars($search); ?>">
<select name="nivel" class="form-control">
<option value="">-- Todos los Niveles --</option>
<option value="info" <?php echo $nivel === 'info' ? 'selected' : ''; ?>>Info</option>
<option value="warning" <?php echo $nivel === 'warning' ? 'selected' : ''; ?>>Warning</option>
<option value="error" <?php echo $nivel === 'error' ? 'selected' : ''; ?>>Error</option>
</select>
<select name="origen" class="form-control">
<option value="">-- Todos los Orígenes --</option>
<option value="sistema" <?php echo $origen === 'sistema' ? 'selected' : ''; ?>>Sistema</option>
<option value="usuario" <?php echo $origen === 'usuario' ? 'selected' : ''; ?>>Usuario</option>
<option value="bot" <?php echo $origen === 'bot' ? 'selected' : ''; ?>>Bot</option>
<option value="webhook" <?php echo $origen === 'webhook' ? 'selected' : ''; ?>>Webhook</option>
</select>
<button type="submit" class="btn btn-primary">
<i class="fas fa-filter"></i> Filtrar
</button>
<?php if ($nivel || $origen || $search): ?>
<a href="list.php" class="btn btn-secondary">Limpiar</a>
<?php endif; ?>
</form>
<table>
<thead>
<tr>
<th>Fecha</th>
<th>Nivel</th>
<th>Origen</th>
<th>Descripción</th>
<th>Usuario</th>
<th>Detalles</th>
</tr>
</thead>
<tbody>
<?php if (empty($logs)): ?>
<tr><td colspan="6" style="text-align:center; color:#666;">No hay registros encontrados.</td></tr>
<?php else: ?>
<?php foreach ($logs as $log): ?>
<tr>
<td style="font-size: 14px; color: #666;"><?php echo $log['fecha']; ?></td>
<td>
<span class="badge badge-<?php echo $log['nivel']; ?>">
<?php echo strtoupper($log['nivel']); ?>
</span>
</td>
<td><?php echo ucfirst($log['origen']); ?></td>
<td><?php echo htmlspecialchars(substr($log['descripcion'], 0, 100)) . (strlen($log['descripcion']) > 100 ? '...' : ''); ?></td>
<td><?php echo $log['username'] ? htmlspecialchars($log['username']) : '-'; ?></td>
<td>
<?php if ($log['datos_json']): ?>
<button class="btn btn-secondary" style="padding: 5px 10px; font-size: 12px;"
onclick='showDetails(<?php echo json_encode($log['datos_json']); ?>)'>
<i class="fas fa-code"></i> JSON
</button>
<?php else: ?>
<span style="color:#ccc;">-</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<!-- Paginación -->
<?php if ($totalPages > 1): ?>
<div class="pagination">
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
<a href="?page=<?php echo $i; ?>&nivel=<?php echo $nivel; ?>&origen=<?php echo $origen; ?>&search=<?php echo $search; ?>"
class="<?php echo $i === $page ? 'active' : ''; ?>">
<?php echo $i; ?>
</a>
<?php endfor; ?>
</div>
<?php endif; ?>
</div>
</div>
<!-- Modal Detalles -->
<div id="detailsModal" class="modal">
<div class="modal-content">
<span class="close-modal" onclick="closeModal()">&times;</span>
<h2>Detalles del Log</h2>
<pre id="jsonContent"></pre>
</div>
</div>
<script>
function showDetails(jsonString) {
try {
// Si ya es objeto, usarlo, si es string, parsearlo
const obj = typeof jsonString === 'string' ? JSON.parse(jsonString) : jsonString;
document.getElementById('jsonContent').textContent = JSON.stringify(obj, null, 2);
document.getElementById('detailsModal').style.display = 'block';
} catch (e) {
console.error(e);
alert('Error al parsear JSON');
}
}
function closeModal() {
document.getElementById('detailsModal').style.display = 'none';
}
window.onclick = function(event) {
if (event.target == document.getElementById('detailsModal')) {
closeModal();
}
}
</script>
</body>
</html>