Primer commit del sistema separado falta mejorar mucho
This commit is contained in:
304
telegram/views/commands/list.php
Executable file
304
telegram/views/commands/list.php
Executable file
@@ -0,0 +1,304 @@
|
||||
<?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();
|
||||
|
||||
// Verificar permiso para ver la página de comandos
|
||||
if (!hasPermission('view_commands', 'telegram')) {
|
||||
die('No tienes permiso para ver los comandos de Telegram.');
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
|
||||
// Obtener comandos (plantillas con comando asignado)
|
||||
$stmt = $db->query("
|
||||
SELECT id, nombre, comando, fecha_creacion
|
||||
FROM plantillas_telegram
|
||||
WHERE comando IS NOT NULL AND comando != ''
|
||||
ORDER BY comando ASC
|
||||
");
|
||||
$comandos = $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>Comandos Telegram - 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 {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, var(--telegram-color) 0%, var(--telegram-dark) 100%);
|
||||
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(--telegram-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);
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 600;
|
||||
color: #555;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.command-tag {
|
||||
background: #2b2d31;
|
||||
color: #dbdee1;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--telegram-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--telegram-dark);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #dc3545;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background: #ffc107;
|
||||
color: #212529;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
.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: 30px;
|
||||
border-radius: 15px;
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #eee;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.close {
|
||||
float: right;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-terminal"></i> Comandos Telegram</h1>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<a href="/telegram/dashboard_telegram.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Volver
|
||||
</a>
|
||||
<?php if (hasPermission('manage_templates', 'telegram')): ?>
|
||||
<a href="/telegram/views/templates/create.php" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> Nuevo Comando (Plantilla)
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<?php if (empty($comandos)): ?>
|
||||
<div style="text-align: center; padding: 40px; color: #666;">
|
||||
<i class="fas fa-terminal" style="font-size: 48px; margin-bottom: 20px; color: #ddd;"></i>
|
||||
<h3>No hay comandos configurados</h3>
|
||||
<p>Los comandos se definen al crear o editar una plantilla.</p>
|
||||
<?php if (hasPermission('manage_templates', 'telegram')): ?>
|
||||
<a href="/telegram/views/templates/create.php" class="btn btn-primary" style="margin-top: 10px;">
|
||||
Ir a Plantillas
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Comando</th>
|
||||
<th>Plantilla Asociada</th>
|
||||
<th>Fecha Creación</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($comandos as $cmd): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="command-tag"><?php echo htmlspecialchars($cmd['comando']); ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<i class="fas fa-file-alt"></i> <?php echo htmlspecialchars($cmd['nombre']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo date('d/m/Y', strtotime($cmd['fecha_creacion'])); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (hasPermission('manage_templates', 'telegram')): ?>
|
||||
<a href="/telegram/views/templates/edit.php?id=<?php echo $cmd['id']; ?>" class="btn btn-edit">
|
||||
<i class="fas fa-edit"></i> Editar
|
||||
</a>
|
||||
<button onclick="deleteCommand(<?php echo $cmd['id']; ?>, '<?php echo htmlspecialchars($cmd['comando'], ENT_QUOTES); ?>')" class="btn btn-danger">
|
||||
<i class="fas fa-trash"></i> Eliminar
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts eliminados ya que no se necesita modal local -->
|
||||
|
||||
<script>
|
||||
async function deleteCommand(templateId, commandName) {
|
||||
if (!confirm(`¿Estás seguro de eliminar el comando "${commandName}"? Esto eliminará también la plantilla asociada.`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/templates/delete.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: templateId })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('Comando y plantilla eliminados correctamente.');
|
||||
location.reload(); // Recargar la página para actualizar la lista
|
||||
} else {
|
||||
alert('Error al eliminar el comando: ' + (result.error || 'Error desconocido.'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error al enviar la solicitud de eliminación:', error);
|
||||
alert('Error de conexión al intentar eliminar el comando.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
116
telegram/views/features.php
Executable file
116
telegram/views/features.php
Executable file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../shared/bootstrap.php';
|
||||
|
||||
// El bootstrap.php ya maneja la autenticación
|
||||
if (!hasPermission('view_logs', 'telegram')) {
|
||||
die('No tienes permiso para ver esta página.');
|
||||
}
|
||||
?>
|
||||
<!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>Funciones del Bot de Telegram</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
:root {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, var(--telegram-color) 0%, var(--telegram-dark) 100%);
|
||||
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(--telegram-color); font-size: 24px; }
|
||||
.btn-back {
|
||||
background: #6c757d; color: white; padding: 10px 20px;
|
||||
border-radius: 8px; text-decoration: none; transition: transform 0.2s;
|
||||
}
|
||||
.btn-back:hover { transform: translateY(-2px); }
|
||||
.container { max-width: 1000px; margin: 0 auto; }
|
||||
.card {
|
||||
background: white; border-radius: 15px; padding: 30px;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); margin-bottom: 20px;
|
||||
}
|
||||
.feature {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.feature:last-child { border-bottom: none; }
|
||||
.feature-title { font-size: 18px; font-weight: 700; color: #333; margin-bottom: 8px; }
|
||||
.feature-event { font-size: 14px; color: var(--telegram-color); font-family: monospace; margin-bottom: 8px; }
|
||||
.feature-description { font-size: 15px; color: #666; line-height: 1.6; }
|
||||
code {
|
||||
background-color: #f0f0f0;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-robot"></i> Funciones del Bot de Telegram</h1>
|
||||
<a href="/telegram/dashboard_telegram.php" class="btn-back">← Volver al Dashboard</a>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<div class="feature">
|
||||
<div class="feature-title">Procesador de Mensajes Programados y Recurrentes</div>
|
||||
<div class="feature-event">Evento: Proceso continuo en segundo plano</div>
|
||||
<p class="feature-description">
|
||||
Un proceso automático se ejecuta constantemente para revisar la base de datos. Si encuentra mensajes programados cuya fecha de envío ha llegado, los envía. También gestiona los mensajes recurrentes (diarios, semanales, mensuales), calculando y enviándolos en la próxima fecha programada.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<div class="feature-title">Captura Automática de Destinatarios</div>
|
||||
<div class="feature-event">Evento: Al recibir un mensaje o interacción</div>
|
||||
<p class="feature-description">
|
||||
Para facilitar el envío de mensajes, el bot registra automáticamente la información de los usuarios y grupos que interactúan con él.
|
||||
<br>- <strong>Al recibir un mensaje:</strong> Registra o actualiza al autor del mensaje y al chat (grupo o chat privado) donde se envió.
|
||||
<br>- <strong>Al recibir una interacción de botón:</strong> Registra o actualiza al usuario que presionó el botón.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<div class="feature-title">Comandos</div>
|
||||
<div class="feature-event">Evento: Mensaje que empieza con /</div>
|
||||
<p class="feature-description">
|
||||
El bot responde a comandos enviados en los chats.
|
||||
<br>- <code>/start</code>: Envía un simple mensaje de saludo.
|
||||
<br>- <code>/help</code>: Envía un mensaje con una lista de comandos.
|
||||
<br>- <strong>Comandos de Plantilla:</strong> Si creas una plantilla y le asignas un "Comando de texto" (ej. <code>/oferta</code>), el bot responderá con el contenido de esa plantilla cuando alguien use ese comando.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<div class="feature-title">Bienvenida a Nuevos Miembros</div>
|
||||
<div class="feature-event">Evento: Un nuevo usuario se une a un grupo</div>
|
||||
<p class="feature-description">
|
||||
Cuando un nuevo usuario se une a un grupo donde el bot es administrador, el bot puede enviarle un mensaje de bienvenida personalizado. Este mensaje puede incluir una imagen, texto de bienvenida (usando <code>{usuario}</code> para mencionarlo) y botones para seleccionar un idioma.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<div class="feature-title">Manejo de Interacciones</div>
|
||||
<div class="feature-event">Evento: Clic en un botón de un mensaje del bot</div>
|
||||
<p class="feature-description">
|
||||
El bot puede responder a interacciones, como los clics en botones.
|
||||
<br>- <strong>Botones de Idioma:</strong> Cuando un usuario hace clic en un botón de selección de idioma, el bot guarda su preferencia de idioma en la base de datos para futuras interacciones.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
322
telegram/views/logs/list.php
Executable file
322
telegram/views/logs/list.php
Executable 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_telegram WHERE $whereClause");
|
||||
$stmt->execute($params);
|
||||
$totalLogs = $stmt->fetchColumn();
|
||||
$totalPages = ceil($totalLogs / $perPage);
|
||||
|
||||
// Obtener logs
|
||||
$stmt = $db->prepare("
|
||||
SELECT l.*, u.username
|
||||
FROM logs_telegram 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 Telegram - 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 {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
--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(--telegram-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(--telegram-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(--telegram-color);
|
||||
}
|
||||
|
||||
.pagination a.active {
|
||||
background: var(--telegram-color);
|
||||
color: white;
|
||||
border-color: var(--telegram-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="/telegram/dashboard_telegram.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()">×</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>
|
||||
635
telegram/views/messages/create.php
Executable file
635
telegram/views/messages/create.php
Executable file
@@ -0,0 +1,635 @@
|
||||
<?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();
|
||||
|
||||
// Verificar permiso para enviar mensajes
|
||||
if (!hasPermission('send_messages', 'telegram')) {
|
||||
die('No tienes permiso para crear y enviar mensajes de Telegram.');
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
|
||||
// Obtener plantillas para el selector
|
||||
$stmt = $db->query("SELECT id, nombre, contenido FROM plantillas_telegram ORDER BY nombre ASC");
|
||||
$plantillas = $stmt->fetchAll();
|
||||
|
||||
// Obtener destinatarios guardados (si existen)
|
||||
$stmt = $db->query("SELECT id, nombre, telegram_id as identificador, tipo FROM destinatarios_telegram ORDER BY nombre ASC");
|
||||
$destinatarios = $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>Crear Mensaje Telegram - Sistema de Bots</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||
<style>
|
||||
:root {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, var(--telegram-color) 0%, var(--telegram-dark) 100%);
|
||||
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(--telegram-color);
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
outline: none;
|
||||
border-color: var(--telegram-color);
|
||||
}
|
||||
|
||||
.form-help {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--telegram-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--telegram-dark);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-top: 30px;
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
/* Select2 Customization */
|
||||
.select2-container--default .select2-selection--multiple {
|
||||
border: 2px solid #e0e0e0 !important;
|
||||
border-radius: 8px !important;
|
||||
min-height: 45px;
|
||||
}
|
||||
.select2-container--default.select2-container--focus .select2-selection--multiple {
|
||||
border-color: var(--telegram-color) !important;
|
||||
}
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: var(--telegram-color);
|
||||
color: white;
|
||||
border: 1px solid var(--telegram-dark);
|
||||
border-radius: 4px;
|
||||
padding: 3px 8px;
|
||||
margin-top: 7px;
|
||||
}
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: white;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Summernote Customization */
|
||||
.note-editor {
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.note-editor.note-frame {
|
||||
border-color: var(--telegram-color);
|
||||
}
|
||||
|
||||
/* Modal Galería */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
margin: 50px auto;
|
||||
padding: 30px;
|
||||
border-radius: 15px;
|
||||
width: 90%;
|
||||
max-width: 900px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.gallery-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.gallery-item {
|
||||
cursor: pointer;
|
||||
border: 3px solid transparent;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.gallery-item:hover {
|
||||
border-color: var(--telegram-color);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.gallery-item img {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.close {
|
||||
float: right;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Scheduled/Recurring styles */
|
||||
.ml-3 { margin-left: 1rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-paper-plane"></i> Crear Mensaje Telegram</h1>
|
||||
<a href="/telegram/dashboard_telegram.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Volver
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="form-container">
|
||||
<div id="alert-messages"></div>
|
||||
|
||||
<form id="messageForm">
|
||||
<div class="form-group">
|
||||
<label for="destinatario_id">Destinatarios (Canal ID o Usuario ID) *</label>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<div style="flex-grow: 1;">
|
||||
<select id="destinatario_select" class="form-control" style="width: 100%;" multiple="multiple">
|
||||
<?php foreach ($destinatarios as $dest):
|
||||
$selected = ''; // Lógica para preseleccionar si es necesario
|
||||
// Ejemplo: if (in_array($dest['identificador'], $existing_destinatarios)) { $selected = 'selected'; }
|
||||
echo "<option value=\"" . htmlspecialchars($dest['identificador']) . "\" $selected>";
|
||||
echo htmlspecialchars($dest['nombre']) . " (". $dest['tipo'] . ")";
|
||||
echo "</option>";
|
||||
endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex-grow: 1;">
|
||||
<input type="text" id="destinatario_manual" name="destinatario_manual" class="form-control" placeholder="O pega IDs manualmente aquí, separados por comas">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-help">Selecciona uno o varios destinatarios guardados, o ingresa IDs manualmente separados por comas.</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="plantilla_id">Cargar Plantilla (Opcional)</label>
|
||||
<select id="plantilla_id" class="form-control" onchange="loadTemplate(this.value)">
|
||||
<option value="">-- Seleccionar Plantilla --</option>
|
||||
<?php foreach ($plantillas as $plantilla):
|
||||
echo "<option value=\"" . htmlspecialchars($plantilla['id']) . "\">";
|
||||
echo htmlspecialchars($plantilla['nombre']);
|
||||
echo "</option>";
|
||||
endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="contenido">Contenido del Mensaje *</label>
|
||||
<button type="button" onclick="openGallery()" class="btn btn-success" style="margin-bottom: 10px; padding: 5px 10px; font-size: 12px;">
|
||||
<i class="fas fa-images"></i> Insertar Imagen
|
||||
</button>
|
||||
<textarea id="contenido" name="contenido"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Tipo de Envío *</label>
|
||||
<div>
|
||||
<input type="radio" id="send_immediate" name="send_type" value="inmediato" checked>
|
||||
<label for="send_immediate">Inmediato</label>
|
||||
|
||||
<input type="radio" id="send_scheduled" name="send_type" value="programado" class="ml-3">
|
||||
<label for="send_scheduled">Programado</label>
|
||||
|
||||
<input type="radio" id="send_recurring" name="send_type" value="recurrente" class="ml-3">
|
||||
<label for="send_recurring">Recurrente</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="scheduled_options" class="form-group" style="display: none;">
|
||||
<label for="schedule_datetime">Fecha y Hora de Envío *</label>
|
||||
<input type="datetime-local" id="schedule_datetime" name="schedule_datetime" class="form-control">
|
||||
</div>
|
||||
|
||||
<div id="recurring_options" class="form-group" style="display: none;">
|
||||
<label for="recurrence_frequency">Frecuencia de Recurrencia *</label>
|
||||
<select id="recurrence_frequency" name="recurrence_frequency" class="form-control">
|
||||
<option value="diario">Diario</option>
|
||||
<option value="semanal">Semanal</option>
|
||||
<option value="mensual">Mensual</option>
|
||||
</select>
|
||||
|
||||
<div id="recurring_details" style="margin-top: 15px;">
|
||||
<!-- Detalles específicos de recurrencia (día de la semana, día del mes) -->
|
||||
<div id="weekly_options" style="display: none;">
|
||||
<label for="recurrence_day_of_week">Día de la Semana</label>
|
||||
<select id="recurrence_day_of_week" name="recurrence_day_of_week" class="form-control">
|
||||
<option value="1">Lunes</option>
|
||||
<option value="2">Martes</option>
|
||||
<option value="3">Miércoles</option>
|
||||
<option value="4">Jueves</option>
|
||||
<option value="5">Viernes</option>
|
||||
<option value="6">Sábado</option>
|
||||
<option value="7">Domingo</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="monthly_options" style="display: none;">
|
||||
<label for="recurrence_day_of_month">Día del Mes</label>
|
||||
<input type="number" id="recurrence_day_of_month" name="recurrence_day_of_month" class="form-control" min="1" max="31">
|
||||
</div>
|
||||
<label for="recurrence_time">Hora de Envío</label>
|
||||
<input type="time" id="recurrence_time" name="recurrence_time" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary" id="btnEnviar">
|
||||
<i class="fas fa-paper-plane"></i> Enviar Ahora
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="previewMessage()">
|
||||
<i class="fas fa-eye"></i> Vista Previa
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Galería -->
|
||||
<div id="galleryModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" onclick="closeGallery()">×</span>
|
||||
<h2>Galería de Imágenes</h2>
|
||||
<div class="gallery-grid" id="galleryGrid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Templates Data Hidden -->
|
||||
<script>
|
||||
const templates = <?php echo json_encode($plantillas); ?>;
|
||||
</script>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#contenido').summernote({
|
||||
height: 300,
|
||||
toolbar: [
|
||||
['style', ['style']],
|
||||
['font', ['bold', 'underline', 'clear']],
|
||||
['color', ['color']],
|
||||
['para', ['ul', 'ol', 'paragraph']],
|
||||
['insert', ['link']],
|
||||
['view', ['fullscreen', 'codeview', 'help']]
|
||||
]
|
||||
});
|
||||
|
||||
// Inicializar Select2 para selección múltiple
|
||||
$('#destinatario_select').select2({
|
||||
placeholder: "-- Seleccionar Destinatarios Guardados --",
|
||||
allowClear: true // Permite deseleccionar
|
||||
});
|
||||
|
||||
// Sincronizar select con input manual
|
||||
$('#destinatario_select').on('change', function() {
|
||||
const selectedIds = $(this).val() || []; // Array de IDs del select2
|
||||
const manualIds = $('#destinatario_manual').val().split(',').map(id => id.trim()).filter(id => id !== '');
|
||||
|
||||
// Combinar y eliminar duplicados
|
||||
const combinedIds = [...new Set([...selectedIds, ...manualIds])];
|
||||
|
||||
// Actualizar el campo manual para reflejar todas las selecciones y entradas manuales
|
||||
$('#destinatario_manual').val(combinedIds.join(', '));
|
||||
});
|
||||
|
||||
$('#destinatario_manual').on('input', function() {
|
||||
const manualIds = $(this).val().split(',').map(id => id.trim()).filter(id => id !== '');
|
||||
const selectedIds = $('#destinatario_select').val() || []; // IDs del select2
|
||||
|
||||
// Asegurarse de que el select2 no se deseleccione si se añade manualmente
|
||||
// Esto es complejo si se quiere mantener el estado exacto en ambos sentidos.
|
||||
// Para simplificar, solo aseguramos que el input manual tenga todos los IDs.
|
||||
const combinedIds = [...new Set([...manualIds, ...selectedIds])];
|
||||
// Intentar seleccionar en select2 lo que está en manual si existe
|
||||
// No actualizamos directamente el select2.val() para evitar ciclos y complejidades.
|
||||
// El input manual es el que "manda" en caso de conflicto directo.
|
||||
});
|
||||
|
||||
// Lógica para mostrar/ocultar campos de programación/recurrencia
|
||||
const sendTypeRadios = document.querySelectorAll('input[name="send_type"]');
|
||||
const scheduledOptions = document.getElementById('scheduled_options');
|
||||
const recurringOptions = document.getElementById('recurring_options');
|
||||
const recurrenceFrequency = document.getElementById('recurrence_frequency');
|
||||
const weeklyOptions = document.getElementById('weekly_options');
|
||||
const monthlyOptions = document.getElementById('monthly_options');
|
||||
|
||||
function toggleSendTypeOptions() {
|
||||
const selectedSendType = document.querySelector('input[name="send_type"]:checked').value;
|
||||
scheduledOptions.style.display = 'none';
|
||||
recurringOptions.style.display = 'none';
|
||||
|
||||
if (selectedSendType === 'programado') {
|
||||
scheduledOptions.style.display = 'block';
|
||||
} else if (selectedSendType === 'recurrente') {
|
||||
recurringOptions.style.display = 'block';
|
||||
toggleRecurringDetails(); // Mostrar detalles específicos al cargar
|
||||
}
|
||||
}
|
||||
|
||||
function toggleRecurringDetails() {
|
||||
const selectedFrequency = recurrenceFrequency.value;
|
||||
weeklyOptions.style.display = 'none';
|
||||
monthlyOptions.style.display = 'none';
|
||||
|
||||
if (selectedFrequency === 'semanal') {
|
||||
weeklyOptions.style.display = 'block';
|
||||
} else if (selectedFrequency === 'mensual') {
|
||||
monthlyOptions.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializar al cargar la página
|
||||
toggleSendTypeOptions();
|
||||
|
||||
// Escuchar cambios en los tipos de envío
|
||||
sendTypeRadios.forEach(radio => {
|
||||
radio.addEventListener('change', toggleSendTypeOptions);
|
||||
});
|
||||
|
||||
// Escuchar cambios en la frecuencia de recurrencia
|
||||
recurrenceFrequency.addEventListener('change', toggleRecurringDetails);
|
||||
|
||||
});
|
||||
|
||||
function loadTemplate(id) {
|
||||
if (!id) return;
|
||||
const template = templates.find(t => t.id == id);
|
||||
if (template) {
|
||||
if (confirm('¿Reemplazar el contenido actual con la plantilla?')) {
|
||||
$('#contenido').summernote('code', template.contenido);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function openGallery() {
|
||||
$('#galleryModal').show();
|
||||
loadGalleryImages();
|
||||
}
|
||||
|
||||
function closeGallery() {
|
||||
$('#galleryModal').hide();
|
||||
}
|
||||
|
||||
async function loadGalleryImages() {
|
||||
try {
|
||||
const response = await fetch('/gallery/api/list.php');
|
||||
const data = await response.json();
|
||||
|
||||
const grid = document.getElementById('galleryGrid');
|
||||
if (data.success && data.images.length > 0) {
|
||||
grid.innerHTML = data.images.map(img => `
|
||||
<div class="gallery-item" onclick="insertImage('${img.url}')">
|
||||
<img src="${img.url_thumbnail}" alt="${img.nombre_original}">
|
||||
</div>
|
||||
`).join('');
|
||||
} else {
|
||||
grid.innerHTML = '<p>No hay imágenes.</p>';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
function insertImage(url) {
|
||||
const fullUrl = window.location.origin + url;
|
||||
$('#contenido').summernote('insertImage', fullUrl);
|
||||
closeGallery();
|
||||
}
|
||||
|
||||
function previewMessage() {
|
||||
const content = $('#contenido').summernote('code');
|
||||
const win = window.open('', 'Preview', 'width=800,height=600');
|
||||
win.document.write('<div style="padding:20px;font-family:sans-serif;">' + content + '</div>');
|
||||
}
|
||||
|
||||
$('#messageForm').on('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const selectedDestinatarios = $('#destinatario_select').val() || []; // Array de IDs del select2
|
||||
const manualDestinatarios = $('#destinatario_manual').val()
|
||||
.split(',')
|
||||
.map(id => id.trim())
|
||||
.filter(id => id !== '');
|
||||
|
||||
// Combinar y eliminar duplicados de ambos orígenes
|
||||
const destinatarios = [...new Set([...selectedDestinatarios, ...manualDestinatarios])];
|
||||
|
||||
const contenido = $('#contenido').summernote('code');
|
||||
const sendType = document.querySelector('input[name="send_type"]:checked').value;
|
||||
let scheduleData = {};
|
||||
|
||||
if (destinatarios.length === 0 || !contenido) {
|
||||
alert('Por favor selecciona al menos un destinatario y escribe un mensaje.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendType === 'programado') {
|
||||
const scheduleDatetime = $('#schedule_datetime').val();
|
||||
if (!scheduleDatetime) {
|
||||
alert('Por favor, selecciona la fecha y hora de envío programado.');
|
||||
return;
|
||||
}
|
||||
scheduleData = {
|
||||
fecha_envio: scheduleDatetime
|
||||
};
|
||||
} else if (sendType === 'recurrente') {
|
||||
const recurrenceFrequencyVal = $('#recurrence_frequency').val();
|
||||
const recurrenceTime = $('#recurrence_time').val();
|
||||
|
||||
if (!recurrenceFrequencyVal || !recurrenceTime) {
|
||||
alert('Por favor, completa la frecuencia y hora de envío recurrente.');
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleData = {
|
||||
frecuencia: recurrenceFrequencyVal,
|
||||
hora_envio: recurrenceTime
|
||||
};
|
||||
|
||||
if (recurrenceFrequencyVal === 'semanal') {
|
||||
const dayOfWeek = $('#recurrence_day_of_week').val();
|
||||
if (!dayOfWeek) {
|
||||
alert('Por favor, selecciona el día de la semana para el envío recurrente.');
|
||||
return;
|
||||
}
|
||||
scheduleData.dia_semana = dayOfWeek;
|
||||
} else if (recurrenceFrequencyVal === 'mensual') {
|
||||
const dayOfMonth = $('#recurrence_day_of_month').val();
|
||||
if (!dayOfMonth || dayOfMonth < 1 || dayOfMonth > 31) {
|
||||
alert('Por favor, ingresa un día válido del mes (1-31) para el envío recurrente.');
|
||||
return;
|
||||
}
|
||||
scheduleData.dia_mes = dayOfMonth;
|
||||
}
|
||||
}
|
||||
|
||||
if (!confirm(`¿Enviar mensaje (${sendType}) a ${destinatarios.length} destinatario(s)?`)) return;
|
||||
|
||||
$('#btnEnviar').prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Enviando...');
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/messages/send.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
destinatario_id: destinatarios, // Ahora puede ser un array
|
||||
contenido: contenido,
|
||||
tipo_envio: sendType,
|
||||
...scheduleData // Añadir datos de programación/recurrencia
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('¡Mensaje enviado correctamente!');
|
||||
window.location.href = '/telegram/views/messages/sent.php';
|
||||
} else {
|
||||
alert('Error: ' + (result.error || 'Error desconocido'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert('Error de conexión');
|
||||
} finally {
|
||||
$('#btnEnviar').prop('disabled', false).html('<i class="fas fa-paper-plane"></i> Enviar Ahora');
|
||||
}
|
||||
});
|
||||
|
||||
// Cerrar modal click fuera
|
||||
window.onclick = function(event) {
|
||||
if (event.target == document.getElementById('galleryModal')) {
|
||||
closeGallery();
|
||||
}
|
||||
}
|
||||
|
||||
function showAlert(message, type) {
|
||||
const alertDiv = `<div class="alert alert-\"${type}\"">${message}</div>`;
|
||||
$('#alert-messages').html(alertDiv);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
6
telegram/views/messages/php_errors.log
Executable file
6
telegram/views/messages/php_errors.log
Executable file
@@ -0,0 +1,6 @@
|
||||
[30-Nov-2025 15:24:34 America/Mexico_City] PHP Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number in /var/www/html/bot/telegram/views/messages/sent.php:51
|
||||
Stack trace:
|
||||
#0 /var/www/html/bot/telegram/views/messages/sent.php(51): PDOStatement->execute()
|
||||
#1 {main}
|
||||
thrown in /var/www/html/bot/telegram/views/messages/sent.php on line 51
|
||||
[30-Nov-2025 16:36:16 America/Mexico_City] PHP Deprecated: strtotime(): Passing null to parameter #1 ($datetime) of type string is deprecated in /var/www/html/bot/telegram/views/messages/sent.php on line 279
|
||||
373
telegram/views/messages/sent.php
Executable file
373
telegram/views/messages/sent.php
Executable file
@@ -0,0 +1,373 @@
|
||||
<?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']) ? (int)$_GET['page'] : 1;
|
||||
$limit = 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
// Obtener estado de filtro si existe
|
||||
$filterStatus = $_GET['status'] ?? 'todos'; // Default a 'todos'
|
||||
|
||||
// Construir la cláusula WHERE para filtrar por estado
|
||||
$whereClause = "WHERE m.estado != 'deshabilitado'"; // No mostrar deshabilitados por defecto en la lista principal
|
||||
$params = [];
|
||||
|
||||
if ($filterStatus !== 'todos') {
|
||||
$whereClause = "WHERE m.estado = ?";
|
||||
$params[] = $filterStatus;
|
||||
}
|
||||
|
||||
|
||||
// Obtener total de mensajes (según filtro)
|
||||
$stmt = $db->prepare("SELECT COUNT(*) FROM mensajes_telegram m {$whereClause}");
|
||||
$stmt->execute($params);
|
||||
$totalMessages = $stmt->fetchColumn();
|
||||
$totalPages = ceil($totalMessages / $limit);
|
||||
|
||||
// Obtener mensajes (según filtro)
|
||||
$stmt = $db->prepare("
|
||||
SELECT m.*, u.username
|
||||
FROM mensajes_telegram m
|
||||
LEFT JOIN usuarios u ON m.usuario_id = u.id
|
||||
{$whereClause}
|
||||
ORDER BY m.fecha_envio DESC
|
||||
LIMIT ? OFFSET ?
|
||||
");
|
||||
$stmt->bindValue(count($params) + 1, $limit, PDO::PARAM_INT);
|
||||
$stmt->bindValue(count($params) + 2, $offset, PDO::PARAM_INT);
|
||||
|
||||
// Bind WHERE parameters manually
|
||||
foreach ($params as $k => $v) {
|
||||
$stmt->bindValue($k + 1, $v);
|
||||
}
|
||||
|
||||
$stmt->execute();
|
||||
$mensajes = $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>Mensajes - Telegram</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
:root {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
--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(--telegram-color); font-size: 24px; }
|
||||
|
||||
.container { max-width: 1200px; margin: 0 auto; }
|
||||
|
||||
.messages-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.message-card {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.message-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.message-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.message-dest {
|
||||
font-weight: 600;
|
||||
color: var(--telegram-color);
|
||||
background: #eef0ff;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.message-status {
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
text-transform: capitalize;
|
||||
color: white;
|
||||
}
|
||||
.status-enviado { background-color: var(--success); }
|
||||
.status-pendiente { background-color: var(--warning); color: #333; }
|
||||
.status-fallido { background-color: var(--danger); }
|
||||
.status-deshabilitado { background-color: var(--secondary-color); }
|
||||
|
||||
.message-content {
|
||||
background: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.message-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--telegram-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.page-link {
|
||||
background: white;
|
||||
color: var(--telegram-color);
|
||||
padding: 8px 12px;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.page-link.active {
|
||||
background: var(--telegram-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
justify-content: center;
|
||||
}
|
||||
.filter-buttons .btn {
|
||||
padding: 8px 15px;
|
||||
font-size: 13px;
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.filter-buttons .btn.active {
|
||||
background-color: var(--telegram-color);
|
||||
color: white;
|
||||
border-color: var(--telegram-color);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-history"></i> Historial de Mensajes Telegram</h1>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<a href="/telegram/dashboard_telegram.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Volver
|
||||
</a>
|
||||
<a href="create.php" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> Nuevo Mensaje
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="filter-buttons">
|
||||
<a href="?status=todos" class="btn <?php echo $filterStatus === 'todos' ? 'active' : ''; ?>">Todos</a>
|
||||
<a href="?status=enviado" class="btn <?php echo $filterStatus === 'enviado' ? 'active' : ''; ?>">Enviados</a>
|
||||
<a href="?status=pendiente" class="btn <?php echo $filterStatus === 'pendiente' ? 'active' : ''; ?>">Pendientes</a>
|
||||
<a href="?status=fallido" class="btn <?php echo $filterStatus === 'fallido' ? 'active' : ''; ?>">Fallidos</a>
|
||||
<a href="?status=deshabilitado" class="btn <?php echo $filterStatus === 'deshabilitado' ? 'active' : ''; ?>">Deshabilitados</a>
|
||||
</div>
|
||||
|
||||
<?php if (empty($mensajes)): ?>
|
||||
<div class="empty-state">
|
||||
<i class="fas fa-inbox" style="font-size: 48px; margin-bottom: 20px; color: #ddd;"></i>
|
||||
<h2>No hay mensajes en este estado</h2>
|
||||
<p>Los mensajes que cumplan este criterio aparecerán aquí.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="messages-list">
|
||||
<?php foreach ($mensajes as $msg): ?>
|
||||
<div class="message-card">
|
||||
<div class="message-header">
|
||||
<div>
|
||||
Enviado a: <span class="message-dest"><?php echo htmlspecialchars($msg['chat_id']); ?></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="message-status status-<?php echo htmlspecialchars($msg['estado']); ?>">
|
||||
<?php echo htmlspecialchars($msg['estado']); ?>
|
||||
</span>
|
||||
<i class="fas fa-clock" style="margin-left: 10px;"></i> <?php echo date('d/m/Y H:i', strtotime($msg['fecha_envio'] ?? 'now')); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="message-content"><?php echo strip_tags($msg['contenido']); ?></div>
|
||||
|
||||
<div class="message-footer">
|
||||
<div>
|
||||
<i class="fas fa-user"></i> Por: <?php echo htmlspecialchars($msg['username'] ?? 'Sistema'); ?>
|
||||
</div>
|
||||
<div>
|
||||
ID Telegram: <?php echo htmlspecialchars($msg['mensaje_telegram_id'] ?? 'N/A'); ?>
|
||||
<button class="btn btn-warning btn-sm" onclick="retryMessage(<?php echo $msg['id']; ?>)" style="margin-left: 15px;">
|
||||
<i class="fas fa-sync-alt"></i> Reintentar
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="deleteMessage(<?php echo $msg['id']; ?>)" style="margin-left: 5px;">
|
||||
<i class="fas fa-trash"></i> Eliminar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($totalPages > 1): ?>
|
||||
<div class="pagination">
|
||||
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
|
||||
<a href="?page=<?php echo $i; ?>&status=<?php echo htmlspecialchars($filterStatus); ?>" class="page-link <?php echo $i === $page ? 'active' : ''; ?>">
|
||||
<?php echo $i; ?>
|
||||
</a>
|
||||
<?php endfor; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function retryMessage(messageId) {
|
||||
if (!confirm('¿Estás seguro de que quieres volver a poner este mensaje en la cola como "pendiente"?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/messages/retry.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: messageId })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('Mensaje marcado como pendiente.');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error al reintentar el mensaje: ' + (result.error || 'Error desconocido.'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error al enviar la solicitud de reintento:', error);
|
||||
alert('Error de conexión al intentar reintentar el mensaje.');
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteMessage(messageId) {
|
||||
if (!confirm('¿Estás seguro de que quieres eliminar/deshabilitar este mensaje?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/messages/delete.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: messageId })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('Mensaje deshabilitado correctamente.');
|
||||
location.reload(); // Recargar la página para actualizar la lista
|
||||
} else {
|
||||
alert('Error al deshabilitar el mensaje: ' + (result.error || 'Error desconocido.'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error al enviar la solicitud de eliminación:', error);
|
||||
alert('Error de conexión al intentar deshabilitar el mensaje.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
461
telegram/views/recipients/list.php
Executable file
461
telegram/views/recipients/list.php
Executable file
@@ -0,0 +1,461 @@
|
||||
<?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();
|
||||
|
||||
// Verificar permiso para ver la página de destinatarios
|
||||
if (!hasPermission('view_recipients', 'telegram')) {
|
||||
die('No tienes permiso para ver los destinatarios de Telegram.');
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
|
||||
// Obtener destinatarios
|
||||
$stmt = $db->query("SELECT * FROM destinatarios_telegram ORDER BY nombre ASC");
|
||||
$destinatarios = $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>Destinatarios Telegram - 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 {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, var(--telegram-color) 0%, var(--telegram-dark) 100%);
|
||||
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(--telegram-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);
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 600;
|
||||
color: #555;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.badge {
|
||||
padding: 5px 10px;
|
||||
border-radius: 15px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-channel {
|
||||
background: #e3f2fd;
|
||||
color: var(--telegram-color);
|
||||
}
|
||||
|
||||
.badge-user {
|
||||
background: #e0f2f1;
|
||||
color: #00796b;
|
||||
}
|
||||
|
||||
.badge-grupo {
|
||||
background: #fff8e1;
|
||||
color: #ff8f00;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--telegram-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--telegram-dark);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #dc3545;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
.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: 30px;
|
||||
border-radius: 15px;
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #eee;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.close {
|
||||
float: right;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-users"></i> Destinatarios Telegram</h1>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<a href="/telegram/dashboard_telegram.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Volver
|
||||
</a>
|
||||
<?php if (hasPermission('manage_recipients', 'telegram')): ?>
|
||||
<button onclick="openCreateModal()" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> Nuevo Destinatario
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<?php if (empty($destinatarios)): ?>
|
||||
<div style="text-align: center; padding: 40px; color: #666;">
|
||||
<i class="fas fa-users-slash" style="font-size: 48px; margin-bottom: 20px; color: #ddd;"></i>
|
||||
<h3>No hay destinatarios guardados</h3>
|
||||
<p>Agrega chats o usuarios frecuentes para enviar mensajes más rápido.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Tipo</th>
|
||||
<th>ID Telegram</th>
|
||||
<th>Fecha Registro</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($destinatarios as $dest): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($dest['nombre']); ?></strong>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge <?php
|
||||
if ($dest['tipo'] == 'canal') echo 'badge-channel';
|
||||
else if ($dest['tipo'] == 'usuario') echo 'badge-user';
|
||||
else if ($dest['tipo'] == 'grupo') echo 'badge-grupo';
|
||||
?>">
|
||||
<?php echo ucfirst($dest['tipo']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><code><?php echo htmlspecialchars($dest['telegram_id']); ?></code></td>
|
||||
<td><?php echo date('d/m/Y', strtotime($dest['fecha_registro'])); ?></td>
|
||||
<td>
|
||||
<?php if (hasPermission('manage_recipients', 'telegram')): ?>
|
||||
<button onclick="editRecipient(<?php echo $dest['id']; ?>, '<?php echo htmlspecialchars($dest['nombre'], ENT_QUOTES); ?>', '<?php echo htmlspecialchars($dest['telegram_id'], ENT_QUOTES); ?>', '<?php echo htmlspecialchars($dest['tipo'], ENT_QUOTES); ?>')" class="btn btn-primary" style="padding: 5px 10px; font-size: 12px;">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php if ($dest['tipo'] === 'usuario' || $dest['tipo'] === 'grupo'): // Only kick users or remove bot from groups ?>
|
||||
<button onclick="kickRecipient(<?php echo $dest['id']; ?>)" class="btn btn-danger" style="padding: 5px 10px; font-size: 12px;">
|
||||
<i class="fas fa-user-slash"></i> Expulsar
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<button onclick="deleteRecipient(<?php echo $dest['id']; ?>)" class="btn btn-danger" style="padding: 5px 10px; font-size: 12px;">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Crear -->
|
||||
<div id="createModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" onclick="closeCreateModal()">×</span>
|
||||
<h2 style="margin-bottom: 20px;">Nuevo Destinatario</h2>
|
||||
<form id="createForm">
|
||||
<div class="form-group">
|
||||
<label>Nombre (Alias)</label>
|
||||
<input type="text" name="nombre" class="form-control" required placeholder="Ej: Canal General">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>ID de Telegram</label>
|
||||
<input type="text" name="telegram_id" class="form-control" required placeholder="Ej: 123456789012345678">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Tipo</label>
|
||||
<select name="tipo" class="form-control">
|
||||
<option value="canal">Canal</option>
|
||||
<option value="usuario">Usuario (DM)</option>
|
||||
<option value="grupo">Grupo</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%;">Guardar</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Editar -->
|
||||
<div id="editModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" onclick="closeEditModal()">×</span>
|
||||
<h2 style="margin-bottom: 20px;">Editar Destinatario</h2>
|
||||
<form id="editForm">
|
||||
<input type="hidden" id="edit_id" name="id">
|
||||
<div class="form-group">
|
||||
<label>Nombre (Alias)</label>
|
||||
<input type="text" id="edit_nombre" name="nombre" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>ID de Telegram</label>
|
||||
<input type="text" id="edit_telegram_id" name="telegram_id" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Tipo</label>
|
||||
<select id="edit_tipo" name="tipo" class="form-control">
|
||||
<option value="canal">Canal</option>
|
||||
<option value="usuario">Usuario (DM)</option>
|
||||
<option value="grupo">Grupo</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%;">Guardar Cambios</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function openCreateModal() {
|
||||
document.getElementById('createModal').style.display = 'block';
|
||||
}
|
||||
|
||||
function closeCreateModal() {
|
||||
document.getElementById('createModal').style.display = 'none';
|
||||
}
|
||||
|
||||
function openEditModal() {
|
||||
document.getElementById('editModal').style.display = 'block';
|
||||
}
|
||||
|
||||
function closeEditModal() {
|
||||
document.getElementById('editModal').style.display = 'none';
|
||||
}
|
||||
|
||||
function editRecipient(id, nombre, telegram_id, tipo) {
|
||||
document.getElementById('edit_id').value = id;
|
||||
document.getElementById('edit_nombre').value = nombre;
|
||||
document.getElementById('edit_telegram_id').value = telegram_id;
|
||||
document.getElementById('edit_tipo').value = tipo;
|
||||
openEditModal();
|
||||
}
|
||||
|
||||
document.getElementById('createForm').onsubmit = async function(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
const data = Object.fromEntries(formData.entries());
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/recipients/create.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert('Error de conexión');
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('editForm').onsubmit = async function(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
const data = Object.fromEntries(formData.entries());
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/recipients/edit.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert('Error de conexión');
|
||||
}
|
||||
};
|
||||
|
||||
async function deleteRecipient(id) {
|
||||
if (!confirm('¿Eliminar este destinatario?')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/recipients/delete.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({id})
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert('Error de conexión');
|
||||
}
|
||||
}
|
||||
|
||||
async function kickRecipient(id) {
|
||||
if (!confirm('¿Estás seguro de intentar expulsar/remover este destinatario de Telegram? Para usuarios, esto solo lo eliminará de la base de datos local (requiere chat_id para expulsión real). Para chats/canales/grupos, el bot intentará abandonarlos.')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/recipients/kick.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({id})
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('Destinatario procesado para expulsión/eliminación.');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error al expulsar/remover: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert('Error de conexión');
|
||||
}
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
if (event.target == document.getElementById('createModal')) {
|
||||
closeCreateModal();
|
||||
}
|
||||
if (event.target == document.getElementById('editModal')) {
|
||||
closeEditModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1
telegram/views/recipients/php_errors.log
Executable file
1
telegram/views/recipients/php_errors.log
Executable file
@@ -0,0 +1 @@
|
||||
[29-Nov-2025 21:47:51 America/Mexico_City] PHP Fatal error: Cannot redeclare hasPermission() (previously declared in /var/www/html/bot/shared/utils/helpers.php:97) in /var/www/html/bot/shared/auth/jwt.php on line 216
|
||||
519
telegram/views/templates/create.php
Executable file
519
telegram/views/templates/create.php
Executable file
@@ -0,0 +1,519 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
require_once __DIR__ . '/../../../shared/utils/helpers.php';
|
||||
require_once __DIR__ . '/../../../shared/auth/jwt.php';
|
||||
|
||||
$userData = JWTAuth::requireAuth();
|
||||
|
||||
// Verificar permiso para ver y crear plantillas
|
||||
if (!hasPermission('manage_templates', 'telegram')) {
|
||||
die('No tienes permiso para crear plantillas de Telegram.');
|
||||
}
|
||||
|
||||
// PHP logic for initial display, not for form processing
|
||||
$error = $_GET['error'] ?? '';
|
||||
$success = $_GET['success'] ?? '';
|
||||
?>
|
||||
<!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>Crear Plantilla - Telegram</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.css" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, var(--telegram-color) 0%, var(--telegram-dark) 100%);
|
||||
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(--telegram-color);
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-group input[type="text"] {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-group input[type="text"]:focus {
|
||||
outline: none;
|
||||
border-color: var(--telegram-color);
|
||||
}
|
||||
|
||||
.form-help {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 12px 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background: #fee;
|
||||
color: #c33;
|
||||
border-left: 4px solid #c33;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: #efe;
|
||||
color: #3c3;
|
||||
border-left: 4px solid #3c3;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--telegram-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--telegram-dark);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
background: #218838;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.note-editor {
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.note-editor.note-frame {
|
||||
border-color: var(--telegram-color);
|
||||
}
|
||||
|
||||
/* Modal de galería */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
margin: 50px auto;
|
||||
padding: 30px;
|
||||
border-radius: 15px;
|
||||
width: 90%;
|
||||
max-width: 900px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.modal-header h2 {
|
||||
color: var(--telegram-color);
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.gallery-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.gallery-item {
|
||||
cursor: pointer;
|
||||
border: 3px solid transparent;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.gallery-item:hover {
|
||||
border-color: var(--telegram-color);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.gallery-item img {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
border: 2px dashed #ddd;
|
||||
border-radius: 10px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-area:hover {
|
||||
border-color: var(--telegram-color);
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.upload-area input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-plus"></i> Crear Plantilla Telegram</h1>
|
||||
<a href="list.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Volver
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="form-container">
|
||||
<div id="alert-messages">
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-error"><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success"><?php echo htmlspecialchars($success); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<form id="createTemplateForm">
|
||||
<div class="form-group">
|
||||
<label for="nombre">Nombre de la Plantilla *</label>
|
||||
<input type="text" id="nombre" name="nombre" required value="">
|
||||
<div class="form-help">Nombre descriptivo para identificar la plantilla</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="comando">Comando (opcional)</label>
|
||||
<input type="text" id="comando" name="comando" placeholder="Ej: /start, /help" value="">
|
||||
<div class="form-help">Comando para invocar esta plantilla en Telegram. Debe ser único.</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="contenido">Contenido *</label>
|
||||
<button type="button" onclick="openGallery()" class="btn btn-success" style="margin-bottom: 10px;">
|
||||
<i class="fas fa-images"></i> Insertar Imagen
|
||||
</button>
|
||||
<textarea id="contenido" name="contenido"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save"></i> Guardar Plantilla
|
||||
</button>
|
||||
<button type="button" onclick="previewContent()" class="btn btn-secondary">
|
||||
<i class="fas fa-eye"></i> Vista Previa
|
||||
</button>
|
||||
<a href="list.php" class="btn btn-secondary">
|
||||
<i class="fas fa-times"></i> Cancelar
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal de Galería -->
|
||||
<div id="galleryModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2><i class="fas fa-images"></i> Galería de Imágenes</h2>
|
||||
<span class="close" onclick="closeGallery()">×</span>
|
||||
</div>
|
||||
|
||||
<div class="upload-area" onclick="document.getElementById('fileInput').click()">
|
||||
<i class="fas fa-cloud-upload-alt" style="font-size: 48px; color: #ddd;"></i>
|
||||
<p style="margin-top: 10px; color: #666;">Haz clic para subir una imagen o arrastra aquí</p>
|
||||
<input type="file" id="fileInput" accept="image/*" onchange="uploadImage(this)">
|
||||
</div>
|
||||
|
||||
<div class="gallery-grid" id="galleryGrid">
|
||||
<p style="text-align: center; color: #999;">Cargando imágenes...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#contenido').summernote({
|
||||
height: 300,
|
||||
toolbar: [
|
||||
['style', ['style']],
|
||||
['font', ['bold', 'underline', 'clear']],
|
||||
['color', ['color']],
|
||||
['para', ['ul', 'ol', 'paragraph']],
|
||||
['table', ['table']],
|
||||
['insert', ['link']],
|
||||
['view', ['fullscreen', 'codeview', 'help']]
|
||||
],
|
||||
placeholder: 'Escribe el contenido de tu plantilla aquí...'
|
||||
});
|
||||
|
||||
// Handle form submission via Fetch API
|
||||
$('#createTemplateForm').on('submit', async function(e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
|
||||
const nombre = $('#nombre').val();
|
||||
const comando = $('#comando').val();
|
||||
const contenido = $('#contenido').summernote('code'); // Get content from Summernote
|
||||
|
||||
// Clear previous alerts
|
||||
$('#alert-messages').empty();
|
||||
|
||||
if (!nombre || !contenido) {
|
||||
showAlert('El nombre y el contenido son obligatorios.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/templates/create.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ nombre, comando, contenido })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showAlert('Plantilla creada correctamente.', 'success');
|
||||
setTimeout(() => {
|
||||
window.location.href = 'list.php';
|
||||
}, 1500); // Redirect after a short delay
|
||||
} else {
|
||||
showAlert(result.error || 'Error desconocido al crear la plantilla.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error al enviar la solicitud:', error);
|
||||
showAlert('Error de conexión al guardar la plantilla.', 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function openGallery() {
|
||||
document.getElementById('galleryModal').style.display = 'block';
|
||||
loadGallery();
|
||||
}
|
||||
|
||||
function closeGallery() {
|
||||
document.getElementById('galleryModal').style.display = 'none';
|
||||
}
|
||||
|
||||
async function loadGallery() {
|
||||
try {
|
||||
const response = await fetch('/gallery/api/list.php');
|
||||
const data = await response.json();
|
||||
|
||||
const grid = document.getElementById('galleryGrid');
|
||||
|
||||
if (data.success && data.images.length > 0) {
|
||||
grid.innerHTML = data.images.map(img => `
|
||||
<div class="gallery-item" onclick="insertImage('${img.url}')">
|
||||
<img src="${img.url_thumbnail}" alt="${img.nombre_original}">
|
||||
</div>
|
||||
`).join('');
|
||||
} else {
|
||||
grid.innerHTML = '<p style="text-align: center; color: #999;">No hay imágenes disponibles</p>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error cargando galería:', error);
|
||||
document.getElementById('galleryGrid').innerHTML = '<p style="text-align: center; color: #c33;">Error cargando imágenes</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function insertImage(url) {
|
||||
const fullUrl = window.location.origin + url;
|
||||
$('#contenido').summernote('insertImage', fullUrl);
|
||||
closeGallery();
|
||||
}
|
||||
|
||||
async function uploadImage(input) {
|
||||
if (!input.files || !input.files[0]) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('image', input.files[0]);
|
||||
|
||||
try {
|
||||
const response = await fetch('/gallery/api/upload.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
alert('Imagen subida correctamente');
|
||||
loadGallery();
|
||||
} else {
|
||||
alert('Error: ' + data.error);
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error al subir la imagen');
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
input.value = '';
|
||||
}
|
||||
|
||||
function previewContent() {
|
||||
const content = $('#contenido').summernote('code');
|
||||
const win = window.open('', 'Preview', 'width=800,height=600');
|
||||
win.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Vista Previa</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.preview-container {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="preview-container">
|
||||
${content}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
}
|
||||
|
||||
// Cerrar modal al hacer clic fuera
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('galleryModal');
|
||||
if (event.target == modal) {
|
||||
closeGallery();
|
||||
}
|
||||
}
|
||||
|
||||
function showAlert(message, type) {
|
||||
const alertDiv =
|
||||
`<div class="alert alert-" + type + ">
|
||||
` + message + `
|
||||
</div>`
|
||||
$('#alert-messages').html(alertDiv);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
540
telegram/views/templates/edit.php
Executable file
540
telegram/views/templates/edit.php
Executable file
@@ -0,0 +1,540 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
require_once __DIR__ . '/../../../shared/utils/helpers.php';
|
||||
require_once __DIR__ . '/../../../shared/auth/jwt.php';
|
||||
require_once __DIR__ . '/../../../shared/database/connection.php';
|
||||
|
||||
$userData = JWTAuth::requireAuth();
|
||||
|
||||
// Verificar permiso para ver y editar plantillas
|
||||
if (!hasPermission('manage_templates', 'telegram')) {
|
||||
die('No tienes permiso para editar plantillas de Telegram.'); // Mensaje de error más general para evitar leaks
|
||||
}
|
||||
|
||||
// Obtener ID de la plantilla
|
||||
$id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$id) {
|
||||
header('Location: list.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
$stmt = $db->prepare("SELECT * FROM plantillas_telegram WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$plantilla = $stmt->fetch();
|
||||
|
||||
if (!$plantilla) {
|
||||
header('Location: list.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verificar propiedad de la plantilla si no es Admin
|
||||
if ($userData->rol !== 'Admin' && $plantilla['usuario_id'] != $userData->userId) {
|
||||
die('No tienes permiso para editar esta plantilla, ya que no te pertenece.');
|
||||
}
|
||||
|
||||
$error = $_GET['error'] ?? '';
|
||||
$success = $_GET['success'] ?? '';
|
||||
?>
|
||||
<!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>Editar Plantilla - Telegram</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.css" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, var(--telegram-color) 0%, var(--telegram-dark) 100%);
|
||||
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(--telegram-color);
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-group input[type="text"] {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-group input[type="text"]:focus {
|
||||
outline: none;
|
||||
border-color: var(--telegram-color);
|
||||
}
|
||||
|
||||
.form-help {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 12px 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background: #fee;
|
||||
color: #c33;
|
||||
border-left: 4px solid #c33;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: #efe;
|
||||
color: #3c3;
|
||||
border-left: 4px solid #3c3;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--telegram-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--telegram-dark);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
background: #218838;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.note-editor {
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.note-editor.note-frame {
|
||||
border-color: var(--telegram-color);
|
||||
}
|
||||
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
margin: 50px auto;
|
||||
padding: 30px;
|
||||
border-radius: 15px;
|
||||
width: 90%;
|
||||
max-width: 900px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.modal-header h2 {
|
||||
color: var(--telegram-color);
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.gallery-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.gallery-item {
|
||||
cursor: pointer;
|
||||
border: 3px solid transparent;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.gallery-item:hover {
|
||||
border-color: var(--telegram-color);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.gallery-item img {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
border: 2px dashed #ddd;
|
||||
border-radius: 10px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-area:hover {
|
||||
border-color: var(--telegram-color);
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.upload-area input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-edit"></i> Editar Plantilla</h1>
|
||||
<a href="list.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Volver
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="form-container">
|
||||
<div id="alert-messages">
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-error"><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success"><?php echo htmlspecialchars($success); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<form id="editTemplateForm">
|
||||
<input type="hidden" id="templateId" value="<?php echo htmlspecialchars($plantilla['id']); ?>">
|
||||
<div class="form-group">
|
||||
<label for="nombre">Nombre de la Plantilla *</label>
|
||||
<input type="text" id="nombre" name="nombre" required value="<?php echo htmlspecialchars($plantilla['nombre']); ?>">
|
||||
<div class="form-help">Nombre descriptivo para identificar la plantilla</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="comando">Comando (opcional)</label>
|
||||
<input type="text" id="comando" name="comando" placeholder="Ej: /comandos, #asedio" value="<?php echo htmlspecialchars($plantilla['comando'] ?? ''); ?>">
|
||||
<div class="form-help">Comando para invocar esta plantilla en Telegram. Debe ser único.</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="contenido">Contenido *</label>
|
||||
<button type="button" onclick="openGallery()" class="btn btn-success" style="margin-bottom: 10px;">
|
||||
<i class="fas fa-images"></i> Insertar Imagen
|
||||
</button>
|
||||
<textarea id="contenido" name="contenido"><?php echo htmlspecialchars($plantilla['contenido']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save"></i> Guardar Cambios
|
||||
</button>
|
||||
<button type="button" onclick="previewContent()" class="btn btn-secondary">
|
||||
<i class="fas fa-eye"></i> Vista Previa
|
||||
</button>
|
||||
<a href="list.php" class="btn btn-secondary">
|
||||
<i class="fas fa-times"></i> Cancelar
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal de Galería -->
|
||||
<div id="galleryModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2><i class="fas fa-images"></i> Galería de Imágenes</h2>
|
||||
<span class="close" onclick="closeGallery()">×</span>
|
||||
</div>
|
||||
|
||||
<div class="upload-area" onclick="document.getElementById('fileInput').click()">
|
||||
<i class="fas fa-cloud-upload-alt" style="font-size: 48px; color: #ddd;"></i>
|
||||
<p style="margin-top: 10px; color: #666;">Haz clic para subir una imagen o arrastra aquí</p>
|
||||
<input type="file" id="fileInput" accept="image/*" onchange="uploadImage(this)">
|
||||
</div>
|
||||
|
||||
<div class="gallery-grid" id="galleryGrid">
|
||||
<p style="text-align: center; color: #999;">Cargando imágenes...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#contenido').summernote({
|
||||
height: 300,
|
||||
toolbar: [
|
||||
['style', ['style']],
|
||||
['font', ['bold', 'underline', 'clear']],
|
||||
['color', ['color']],
|
||||
['para', ['ul', 'ol', 'paragraph']],
|
||||
['table', ['table']],
|
||||
['insert', ['link']],
|
||||
['view', ['fullscreen', 'codeview', 'help']]
|
||||
]
|
||||
});
|
||||
|
||||
// Handle form submission via Fetch API
|
||||
$('#editTemplateForm').on('submit', async function(e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
|
||||
const id = $('#templateId').val();
|
||||
const nombre = $('#nombre').val();
|
||||
const comando = $('#comando').val();
|
||||
const contenido = $('#contenido').summernote('code'); // Get content from Summernote
|
||||
|
||||
// Clear previous alerts
|
||||
$('#alert-messages').empty();
|
||||
|
||||
if (!nombre || !contenido) {
|
||||
showAlert('El nombre y el contenido son obligatorios.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/templates/edit.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id, nombre, comando, contenido })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showAlert('Plantilla actualizada correctamente.', 'success');
|
||||
// Optionally redirect or update UI
|
||||
} else {
|
||||
showAlert(result.error || 'Error desconocido al actualizar la plantilla.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error al enviar la solicitud:', error);
|
||||
showAlert('Error de conexión al guardar los cambios.', 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function openGallery() {
|
||||
document.getElementById('galleryModal').style.display = 'block';
|
||||
loadGallery();
|
||||
}
|
||||
|
||||
function closeGallery() {
|
||||
document.getElementById('galleryModal').style.display = 'none';
|
||||
}
|
||||
|
||||
async function loadGallery() {
|
||||
try {
|
||||
const response = await fetch('/gallery/api/list.php');
|
||||
const data = await response.json();
|
||||
|
||||
const grid = document.getElementById('galleryGrid');
|
||||
|
||||
if (data.success && data.images.length > 0) {
|
||||
grid.innerHTML = data.images.map(img => `
|
||||
<div class="gallery-item" onclick="insertImage('${img.url}')">
|
||||
<img src="${img.url_thumbnail}" alt="${img.nombre_original}">
|
||||
</div>
|
||||
`).join('');
|
||||
} else {
|
||||
grid.innerHTML = '<p style="text-align: center; color: #999;">No hay imágenes disponibles</p>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error cargando galería:', error);
|
||||
document.getElementById('galleryGrid').innerHTML = '<p style="text-align: center; color: #c33;">Error cargando imágenes</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function insertImage(url) {
|
||||
const fullUrl = window.location.origin + url;
|
||||
$('#contenido').summernote('insertImage', fullUrl);
|
||||
closeGallery();
|
||||
}
|
||||
|
||||
async function uploadImage(input) {
|
||||
if (!input.files || !input.files[0]) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('image', input.files[0]);
|
||||
|
||||
try {
|
||||
const response = await fetch('/gallery/api/upload.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
alert('Imagen subida correctamente');
|
||||
loadGallery();
|
||||
} else {
|
||||
alert('Error: ' + data.error);
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error al subir la imagen');
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
input.value = '';
|
||||
}
|
||||
|
||||
function previewContent() {
|
||||
const content = $('#contenido').summernote('code');
|
||||
const win = window.open('', 'Preview', 'width=800,height=600');
|
||||
win.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Vista Previa</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.preview-container {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="preview-container">
|
||||
${content}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('galleryModal');
|
||||
if (event.target == modal) {
|
||||
closeGallery();
|
||||
}
|
||||
}
|
||||
|
||||
function showAlert(message, type) {
|
||||
const alertDiv =
|
||||
`<div class="alert alert-" + type + ">
|
||||
` + message + `
|
||||
</div>
|
||||
`;
|
||||
$('#alert-messages').html(alertDiv);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
335
telegram/views/templates/list.php
Executable file
335
telegram/views/templates/list.php
Executable file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// Cargar variables de entorno
|
||||
if (file_exists(__DIR__ . '/../../../.env')) {
|
||||
$lines = file(__DIR__ . '/../../../.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
if (strpos(trim($line), '#') === 0) continue;
|
||||
if (strpos($line, '=') === false) continue;
|
||||
list($key, $value) = explode('=', $line, 2);
|
||||
$_ENV[trim($key)] = trim($value);
|
||||
}
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../../../shared/utils/helpers.php';
|
||||
require_once __DIR__ . '/../../../shared/auth/jwt.php';
|
||||
|
||||
$userData = JWTAuth::requireAuth();
|
||||
|
||||
// Verificar permiso para ver la página de plantillas
|
||||
if (!hasPermission('view_templates', 'telegram')) {
|
||||
die('No tienes permiso para ver las plantillas de Telegram.');
|
||||
}
|
||||
?>
|
||||
<!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>Plantillas Telegram - 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 {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, var(--telegram-color) 0%, var(--telegram-dark) 100%);
|
||||
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(--telegram-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);
|
||||
}
|
||||
|
||||
.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;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.btn-primary { background: var(--telegram-color); color: white; }
|
||||
.btn-secondary { background: #6c757d; color: white; }
|
||||
.btn-danger { background: #dc3545; color: white; }
|
||||
|
||||
#templates-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.template-card {
|
||||
background: #f8f9fa;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
border: 2px solid #eee;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.template-card:hover {
|
||||
border-color: var(--telegram-color);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.template-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.template-title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.template-meta {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.template-preview-content {
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 15px;
|
||||
max-height: 100px;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
position: relative;
|
||||
}
|
||||
.template-preview-content::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 30px;
|
||||
background: linear-gradient(transparent, white);
|
||||
}
|
||||
|
||||
.template-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.empty-state, .loading-state, .error-state {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 60px 40px;
|
||||
text-align: center;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.empty-state i, .loading-state i, .error-state i {
|
||||
font-size: 64px;
|
||||
color: #ddd;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.empty-state h2, .loading-state h2, .error-state h2 {
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.empty-state p, .loading-state p, .error-state p {
|
||||
color: #999;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-file-alt"></i> Plantillas de Telegram</h1>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<?php if (hasPermission('manage_templates', 'telegram')): ?>
|
||||
<a href="create.php" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> Nueva Plantilla
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<a href="/telegram/dashboard_telegram.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Volver
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<div id="templates-container">
|
||||
<!-- Templates will be loaded here by JavaScript -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', loadTemplates);
|
||||
|
||||
function escapeHTML(str) {
|
||||
if (str === null || str === undefined) return '';
|
||||
return str.toString().replace(/[&<>"']/g, function(match) {
|
||||
return {
|
||||
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
|
||||
}[match];
|
||||
});
|
||||
}
|
||||
|
||||
async function loadTemplates() {
|
||||
const container = document.getElementById('templates-container');
|
||||
container.innerHTML = `
|
||||
<div class="loading-state">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
<h2>Cargando Plantillas...</h2>
|
||||
</div>`;
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/templates/list.php');
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to load templates');
|
||||
}
|
||||
|
||||
if (result.templates.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<i class="fas fa-file-alt"></i>
|
||||
<h2>No hay plantillas creadas</h2>
|
||||
<p>Crea tu primera plantilla para empezar a enviar mensajes en Telegram</p>
|
||||
<?php if (hasPermission('manage_templates', 'telegram')): ?>
|
||||
<a href="create.php" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> Crear Primera Plantilla
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = '<div class="templates-grid"></div>'; // Clear loading state and add grid
|
||||
const templatesGrid = container.querySelector('.templates-grid');
|
||||
result.templates.forEach(template => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'template-card';
|
||||
|
||||
const commandHTML = template.comando
|
||||
? `<span class="template-command" style="background: #e3f2fd; color: var(--telegram-color); padding: 4px 12px; border-radius: 12px; font-size: 13px; font-weight: 600; font-family: monospace;">${escapeHTML(template.comando)}</span>`
|
||||
: '';
|
||||
|
||||
const contentPreview = document.createElement('div');
|
||||
// Telegram doesn't use HTML in the same way, but it can use Markdown.
|
||||
// For preview, we'll just show plain text or stripped HTML.
|
||||
contentPreview.innerHTML = template.contenido;
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="template-header">
|
||||
<div>
|
||||
<div class="template-title">${escapeHTML(template.nombre)}</div>
|
||||
${commandHTML}
|
||||
</div>
|
||||
</div>
|
||||
<div class="template-meta">
|
||||
<i class="fas fa-user"></i> ${escapeHTML(template.username) || 'Desconocido'}
|
||||
<br>
|
||||
<i class="fas fa-clock"></i> ${new Date(template.fecha_modificacion).toLocaleString()}
|
||||
</div>
|
||||
<div class="template-preview-content">
|
||||
${escapeHTML(contentPreview.textContent || '')}
|
||||
</div>
|
||||
<div class="template-actions">
|
||||
<?php if (hasPermission('manage_templates', 'telegram')): ?>
|
||||
<a href="edit.php?id=${template.id}" class="btn btn-primary" style="font-size: 12px; padding: 5px 10px;">
|
||||
<i class="fas fa-edit"></i> Editar
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if (hasPermission('view_templates', 'telegram')): ?>
|
||||
<a href="preview.php?id=${template.id}" class="btn btn-secondary" style="font-size: 12px; padding: 5px 10px;" target="_blank">
|
||||
<i class="fas fa-eye"></i> Vista Previa
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if (hasPermission('manage_templates', 'telegram')): ?>
|
||||
<button onclick="deleteTemplate(${template.id}, '${escapeHTML(template.nombre)}') " class="btn btn-danger" style="font-size: 12px; padding: 5px 10px;">
|
||||
<i class="fas fa-trash"></i> Eliminar
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
`;
|
||||
templatesGrid.appendChild(card);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading templates:', error);
|
||||
container.innerHTML = `
|
||||
<div class="error-state">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<h2>Error al Cargar</h2>
|
||||
<p>No se pudieron cargar las plantillas. Revisa la consola para más detalles.</p>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteTemplate(id, nombre) {
|
||||
if (!confirm(\`¿Estás seguro de eliminar la plantilla "\${nombre}"?\`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/templates/delete.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: id })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
alert('Plantilla eliminada correctamente');
|
||||
loadTemplates(); // Reload the list dynamically
|
||||
} else {
|
||||
alert('Error al eliminar: ' + (data.error || 'Error desconocido'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting template:', error);
|
||||
alert('Error de conexión al intentar eliminar la plantilla.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
24
telegram/views/templates/php_errors.log
Executable file
24
telegram/views/templates/php_errors.log
Executable file
@@ -0,0 +1,24 @@
|
||||
[29-Nov-2025 14:32:40 America/Mexico_City] PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'p.creador_id' in 'on clause' in /var/www/html/bot/telegram/views/templates/list.php:27
|
||||
Stack trace:
|
||||
#0 /var/www/html/bot/telegram/views/templates/list.php(27): PDO->query()
|
||||
#1 {main}
|
||||
thrown in /var/www/html/bot/telegram/views/templates/list.php on line 27
|
||||
[29-Nov-2025 14:32:47 America/Mexico_City] PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'p.creador_id' in 'on clause' in /var/www/html/bot/telegram/views/templates/list.php:27
|
||||
Stack trace:
|
||||
#0 /var/www/html/bot/telegram/views/templates/list.php(27): PDO->query()
|
||||
#1 {main}
|
||||
thrown in /var/www/html/bot/telegram/views/templates/list.php on line 27
|
||||
[29-Nov-2025 14:36:22 America/Mexico_City] PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'p.creador_id' in 'on clause' in /var/www/html/bot/telegram/views/templates/list.php:27
|
||||
Stack trace:
|
||||
#0 /var/www/html/bot/telegram/views/templates/list.php(27): PDO->query()
|
||||
#1 {main}
|
||||
thrown in /var/www/html/bot/telegram/views/templates/list.php on line 27
|
||||
[29-Nov-2025 14:36:39 America/Mexico_City] PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'p.creador_id' in 'on clause' in /var/www/html/bot/telegram/views/templates/list.php:27
|
||||
Stack trace:
|
||||
#0 /var/www/html/bot/telegram/views/templates/list.php(27): PDO->query()
|
||||
#1 {main}
|
||||
thrown in /var/www/html/bot/telegram/views/templates/list.php on line 27
|
||||
[29-Nov-2025 14:38:04 America/Mexico_City] PHP Warning: file_put_contents(/var/www/html/bot/shared/utils/../logs/telegram/templates.log): Failed to open stream: No such file or directory in /var/www/html/bot/shared/utils/helpers.php on line 40
|
||||
[29-Nov-2025 14:38:38 America/Mexico_City] PHP Warning: file_put_contents(/var/www/html/bot/shared/utils/../logs/telegram/templates.log): Failed to open stream: No such file or directory in /var/www/html/bot/shared/utils/helpers.php on line 40
|
||||
[29-Nov-2025 14:38:47 America/Mexico_City] PHP Warning: file_put_contents(/var/www/html/bot/shared/utils/../logs/telegram/templates.log): Failed to open stream: No such file or directory in /var/www/html/bot/shared/utils/helpers.php on line 40
|
||||
[29-Nov-2025 18:03:02 America/Mexico_City] PHP Warning: file_put_contents(/var/www/html/bot/shared/utils/../logs/telegram/templates.log): Failed to open stream: No such file or directory in /var/www/html/bot/shared/utils/helpers.php on line 40
|
||||
130
telegram/views/templates/preview.php
Executable file
130
telegram/views/templates/preview.php
Executable file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
require_once __DIR__ . '/../../../shared/utils/helpers.php';
|
||||
require_once __DIR__ . '/../../../shared/auth/jwt.php';
|
||||
require_once __DIR__ . '/../../../shared/database/connection.php';
|
||||
|
||||
// Verificar autenticación
|
||||
$userData = JWTAuth::requireAuth();
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$id) {
|
||||
die('ID no proporcionado');
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
$stmt = $db->prepare("SELECT * FROM plantillas_telegram WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$plantilla = $stmt->fetch();
|
||||
|
||||
if (!$plantilla) {
|
||||
die('Plantilla no encontrada');
|
||||
}
|
||||
?>
|
||||
<!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>Vista Previa: <?php echo htmlspecialchars($plantilla['nombre']); ?></title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'gg sans', 'Noto Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
background-color: #313338;
|
||||
color: #dbdee1;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
line-height: 1.375rem;
|
||||
}
|
||||
|
||||
.telegram-message {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background: #313338;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
font-size: 1rem;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Estilos básicos para simular Telegram */
|
||||
strong { font-weight: 700; }
|
||||
em { font-style: italic; }
|
||||
u { text-decoration: underline; }
|
||||
|
||||
a {
|
||||
color: #00a8fc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #2b2d31;
|
||||
padding: 2px;
|
||||
border-radius: 3px;
|
||||
font-family: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #2b2d31;
|
||||
border: 1px solid #1e1f22;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
margin: 6px 0;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0;
|
||||
padding: 0 0 0 4px;
|
||||
border-left: 4px solid #4e5058;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 4px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 8px 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h1 { font-size: 1.5rem; }
|
||||
h2 { font-size: 1.25rem; }
|
||||
h3 { font-size: 1rem; }
|
||||
|
||||
ul, ol {
|
||||
margin: 8px 0;
|
||||
padding-left: 24px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="telegram-message">
|
||||
<div class="message-content">
|
||||
<?php echo $plantilla['contenido']; ?>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
477
telegram/views/welcome/config.php
Executable file
477
telegram/views/welcome/config.php
Executable file
@@ -0,0 +1,477 @@
|
||||
<?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();
|
||||
|
||||
// Verificar permiso para gestionar el mensaje de bienvenida
|
||||
if (!hasPermission('manage_welcome', 'telegram')) {
|
||||
die('No tienes permiso para gestionar la configuración del mensaje de bienvenida de Telegram.');
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
|
||||
// Manejar guardado
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Verificar permiso para la acción de guardar
|
||||
if (!hasPermission('manage_welcome', 'telegram')) {
|
||||
jsonResponse(['success' => false, 'error' => 'No tienes permiso para guardar la configuración del mensaje de bienvenida.'], 403);
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
try {
|
||||
$chat_id = $input['chat_id'] ?? '';
|
||||
$texto = $input['texto'] ?? '';
|
||||
$imagen_id = !empty($input['imagen_id']) ? $input['imagen_id'] : null;
|
||||
$idiomas_habilitados = json_encode($input['idiomas_habilitados'] ?? []); // Guardar como JSON
|
||||
$registrar = isset($input['registrar_usuario']) ? (int)$input['registrar_usuario'] : 1;
|
||||
$activo = isset($input['activo']) ? (int)$input['activo'] : 1;
|
||||
$boton_unirse_texto = trim($input['boton_unirse_texto'] ?? '');
|
||||
$boton_unirse_url = trim($input['boton_unirse_url'] ?? '');
|
||||
|
||||
// Intentar actualizar primero
|
||||
$stmt = $db->prepare("SELECT id FROM bienvenida_telegram LIMIT 1");
|
||||
$stmt->execute();
|
||||
$exists = $stmt->fetchColumn();
|
||||
|
||||
if ($exists) {
|
||||
$stmt = $db->prepare("
|
||||
UPDATE bienvenida_telegram
|
||||
SET chat_id = ?, texto = ?, imagen_id = ?, idiomas_habilitados = ?, registrar_usuario = ?, activo = ?, boton_unirse_texto = ?, boton_unirse_url = ?
|
||||
WHERE id = ?
|
||||
");
|
||||
$stmt->execute([$chat_id, $texto, $imagen_id, $idiomas_habilitados, $registrar, $activo, $boton_unirse_texto, $boton_unirse_url, $exists]);
|
||||
} else {
|
||||
$stmt = $db->prepare("
|
||||
INSERT INTO bienvenida_telegram (chat_id, texto, imagen_id, idiomas_habilitados, registrar_usuario, activo, boton_unirse_texto, boton_unirse_url)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$stmt->execute([$chat_id, $texto, $imagen_id, $idiomas_habilitados, $registrar, $activo, $boton_unirse_texto, $boton_unirse_url]);
|
||||
}
|
||||
|
||||
jsonResponse(['success' => true]);
|
||||
} catch (Exception $e) {
|
||||
jsonResponse(['success' => false, 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Obtener configuración actual
|
||||
$stmt = $db->query("
|
||||
SELECT b.*, g.ruta as imagen_ruta
|
||||
FROM bienvenida_telegram b
|
||||
LEFT JOIN gallery g ON b.imagen_id = g.id
|
||||
LIMIT 1
|
||||
");
|
||||
$config = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Obtener canales destinatarios
|
||||
$stmt = $db->query("SELECT telegram_id, nombre FROM destinatarios_telegram WHERE tipo = 'canal' OR tipo = 'grupo' ORDER BY nombre ASC");
|
||||
$canales = $stmt->fetchAll();
|
||||
|
||||
// Obtener idiomas activos
|
||||
$stmt = $db->query("SELECT id, codigo, nombre FROM idiomas WHERE activo = 1 ORDER BY nombre ASC");
|
||||
$idiomas = $stmt->fetchAll();
|
||||
|
||||
// Decodificar idiomas seleccionados
|
||||
$idiomasSeleccionados = [];
|
||||
if ($config && $config['idiomas_habilitados']) {
|
||||
$idiomasSeleccionados = json_decode($config['idiomas_habilitados'], true) ?? [];
|
||||
}
|
||||
?>
|
||||
<!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>Bienvenida Telegram - Sistema de Bots</title>
|
||||
|
||||
<!-- FontAwesome -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
|
||||
<!-- Summernote CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Select2 CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--telegram-color: #0088cc;
|
||||
--telegram-dark: #006699;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, var(--telegram-color) 0%, var(--telegram-dark) 100%);
|
||||
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(--telegram-color); font-size: 24px; }
|
||||
|
||||
.container { max-width: 1000px; margin: 0 auto; }
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.form-group { margin-bottom: 20px; }
|
||||
.form-group label { display: block; margin-bottom: 8px; font-weight: 600; }
|
||||
.form-control { width: 100%; padding: 10px; border: 2px solid #eee; border-radius: 8px; }
|
||||
|
||||
.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(--telegram-color); color: white; }
|
||||
.btn-secondary { background: #6c757d; color: white; }
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
}
|
||||
.switch input { opacity: 0; width: 0; height: 0; }
|
||||
.slider {
|
||||
position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0;
|
||||
background-color: #ccc; transition: .4s; border-radius: 34px;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute; content: ""; height: 16px; width: 16px; left: 4px; bottom: 4px;
|
||||
background-color: white; transition: .4s; border-radius: 50%;
|
||||
}
|
||||
input:checked + .slider { background-color: var(--telegram-color); }
|
||||
input:checked + .slider:before { transform: translateX(26px); }
|
||||
|
||||
/* Modal Galería */
|
||||
.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: 5% auto; padding: 20px; width: 80%; max-width: 900px; border-radius: 15px; max-height: 80vh; overflow-y: auto; }
|
||||
.gallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 15px; margin-top: 20px; }
|
||||
.gallery-item { border: 2px solid #eee; border-radius: 8px; overflow: hidden; cursor: pointer; transition: all 0.2s; position: relative; }
|
||||
.gallery-item:hover { border-color: var(--telegram-color); transform: translateY(-2px); }
|
||||
.gallery-item.selected { border-color: var(--telegram-color); box-shadow: 0 0 0 3px rgba(88, 101, 242, 0.3); }
|
||||
|
||||
.image-preview {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background: #f8f9fa;
|
||||
border: 2px dashed #ddd;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
.image-preview img { width: 100%; height: 100%; object-fit: contain; }
|
||||
.remove-image {
|
||||
position: absolute; top: 10px; right: 10px;
|
||||
background: rgba(255,0,0,0.8); color: white;
|
||||
border: none; border-radius: 50%; width: 30px; height: 30px;
|
||||
cursor: pointer; display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-handshake"></i> Configuración de Bienvenida</h1>
|
||||
<a href="/telegram/dashboard_telegram.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Volver
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<form id="welcomeForm">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 20px;">
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label>Activar Bienvenida</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" name="activo" <?php echo ($config['activo'] ?? 1) ? 'checked' : ''; ?>>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label>Registrar Usuario en BD</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" name="registrar_usuario" <?php echo ($config['registrar_usuario'] ?? 1) ? 'checked' : ''; ?>>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Canal de Bienvenida</label>
|
||||
<select name="chat_id" class="form-control select2" required>
|
||||
<option value="">-- Seleccionar Canal --</option>
|
||||
<?php foreach ($canales as $canal): ?>
|
||||
<option value="<?php echo $canal['telegram_id']; ?>"
|
||||
<?php echo ($config['chat_id'] ?? '') == $canal['telegram_id'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($canal['nombre']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<small style="color: #666;">Si no aparece, agrégalo en "Destinatarios".</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Idiomas Disponibles (Botones Automáticos)</label>
|
||||
<select name="idiomas_habilitados[]" id="idiomas_habilitados_select" class="form-control" multiple="multiple">
|
||||
<?php foreach ($idiomas as $lang): ?>
|
||||
<option value="<?php echo $lang['codigo']; ?>"
|
||||
<?php echo in_array($lang['codigo'], $idiomasSeleccionados) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($lang['nombre']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<small style="color: #666;">Selecciona los idiomas que se mostrarán como botones en el mensaje de bienvenida.</small>
|
||||
<div style="margin-top: 10px;">
|
||||
<a href="/shared/languages/manager.php" style="font-size: 12px; color: var(--telegram-color); text-decoration: none;">
|
||||
<i class="fas fa-cog"></i> Gestionar idiomas
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Mensaje de Bienvenida</label>
|
||||
<textarea id="summernote" name="texto"><?php echo htmlspecialchars($config['texto'] ?? ''); ?></textarea>
|
||||
<small style="color: #666;">Puedes usar {usuario} para mencionar al nuevo miembro.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Imagen Opcional</label>
|
||||
<input type="hidden" id="imagen_id" name="imagen_id" value="<?php echo htmlspecialchars($config['imagen_id'] ?? ''); ?>">
|
||||
<button type="button" onclick="openGallery()" class="btn btn-secondary" style="margin-bottom: 10px;">
|
||||
<i class="fas fa-image"></i> Seleccionar Imagen
|
||||
</button>
|
||||
<div id="imagePreview" class="image-preview">
|
||||
<?php if (!empty($config['imagen_id']) && !empty($config['imagen_ruta'])): ?>
|
||||
<img src="/gallery/uploads/<?php echo basename($config['imagen_ruta']); ?>" alt="Imagen de bienvenida">
|
||||
<button type="button" class="remove-image" style="display:block" onclick="removeImage()">×</button>
|
||||
<?php else: ?>
|
||||
<span style="color: #ccc;">Sin imagen seleccionada</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="boton_unirse_texto">Texto del Botón "Únete al grupo"</label>
|
||||
<input type="text" id="boton_unirse_texto" name="boton_unirse_texto" class="form-control" value="<?php echo htmlspecialchars($config['boton_unirse_texto'] ?? 'Únete al grupo'); ?>">
|
||||
<small style="color: #666;">Texto que aparecerá en el botón de unirse al grupo/canal.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="boton_unirse_url">URL del Botón "Únete al grupo"</label>
|
||||
<input type="url" id="boton_unirse_url" name="boton_unirse_url" class="form-control" value="<?php echo htmlspecialchars($config['boton_unirse_url'] ?? ''); ?>">
|
||||
<small style="color: #666;">URL del grupo/canal de Telegram al que el usuario será invitado.</small>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
||||
<?php if (hasPermission('manage_welcome', 'telegram')): ?>
|
||||
<button type="submit" class="btn btn-primary" style="flex: 1; justify-content: center;">
|
||||
<i class="fas fa-save"></i> Guardar Configuración
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (hasPermission('manage_welcome', 'telegram')): ?>
|
||||
<button type="button" onclick="sendTestMessage()" class="btn btn-success" style="flex: 1; justify-content: center; background: #28a745;">
|
||||
<i class="fas fa-paper-plane"></i> Probar Mensaje
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Librerías JS -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#summernote').summernote({
|
||||
height: 200,
|
||||
toolbar: [
|
||||
['style', ['bold', 'italic', 'underline', 'clear']],
|
||||
['para', ['ul', 'ol']],
|
||||
['insert', ['link']],
|
||||
['view', ['codeview']]
|
||||
]
|
||||
});
|
||||
|
||||
$('.select2').select2();
|
||||
$('#idiomas_habilitados_select').select2(); // Inicializar el select2 para idiomas
|
||||
|
||||
// Galería
|
||||
function openGallery() {
|
||||
document.getElementById('galleryModal').style.display = 'block';
|
||||
loadGalleryImages();
|
||||
}
|
||||
|
||||
function closeGallery() {
|
||||
document.getElementById('galleryModal').style.display = 'none';
|
||||
}
|
||||
|
||||
async function loadGalleryImages() {
|
||||
const container = document.getElementById('galleryContainer');
|
||||
container.innerHTML = '<p>Cargando...</p>';
|
||||
|
||||
try {
|
||||
const response = await fetch('/gallery/api/list.php');
|
||||
const data = await response.json();
|
||||
|
||||
container.innerHTML = '';
|
||||
if (data.images && data.images.length > 0) {
|
||||
data.images.forEach(img => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'gallery-item';
|
||||
// La API devuelve url_thumbnail (ruta completa) y nombre_original
|
||||
div.innerHTML = `<img src="${img.url_thumbnail}" alt="${img.nombre_original}">`;
|
||||
// Pasamos img.nombre que es el nombre del archivo físico
|
||||
div.onclick = () => selectImage(img.id, img.nombre, img.ruta); // Pasar también la ruta completa para preview
|
||||
container.appendChild(div);
|
||||
});
|
||||
} else {
|
||||
container.innerHTML = '<p>No hay imágenes en la galería.</p>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
container.innerHTML = '<p>Error cargando imágenes.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function selectImage(id, filename, ruta_completa) {
|
||||
document.getElementById('imagen_id').value = id;
|
||||
const preview = document.getElementById('imagePreview');
|
||||
preview.innerHTML = `
|
||||
<img src="${ruta_completa}" alt="Imagen de bienvenida">
|
||||
<button type="button" class="remove-image" style="display:block" onclick="removeImage()">×</button>
|
||||
`;
|
||||
closeGallery();
|
||||
}
|
||||
|
||||
function removeImage() {
|
||||
document.getElementById('imagen_id').value = '';
|
||||
document.getElementById('imagePreview').innerHTML = `
|
||||
<span style="color: #ccc;">Sin imagen seleccionada</span>
|
||||
`;
|
||||
}
|
||||
|
||||
// Guardar
|
||||
document.getElementById('welcomeForm').onsubmit = async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Recolectar datos del formulario
|
||||
const activo = $('input[name="activo"]').is(':checked') ? 1 : 0;
|
||||
const registrar_usuario = $('input[name="registrar_usuario"]').is(':checked') ? 1 : 0;
|
||||
const chat_id = $('select[name="chat_id"]').val();
|
||||
const texto = $('#summernote').summernote('code');
|
||||
const imagen_id = $('#imagen_id').val();
|
||||
const idiomas_habilitados = $('#idiomas_habilitados_select').val(); // Array de códigos de idioma
|
||||
const boton_unirse_texto = $('#boton_unirse_texto').val();
|
||||
const boton_unirse_url = $('#boton_unirse_url').val();
|
||||
|
||||
const data = {
|
||||
activo: activo,
|
||||
registrar_usuario: registrar_usuario,
|
||||
chat_id: chat_id,
|
||||
texto: texto,
|
||||
imagen_id: imagen_id === '' ? null : imagen_id, // Enviar null si no hay imagen
|
||||
idiomas_habilitados: idiomas_habilitados, // Enviar el array de idiomas
|
||||
boton_unirse_texto: boton_unirse_texto,
|
||||
boton_unirse_url: boton_unirse_url
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(window.location.href, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('Configuración guardada correctamente');
|
||||
} else {
|
||||
alert('Error: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert('Error de conexión');
|
||||
}
|
||||
};
|
||||
|
||||
async function sendTestMessage() {
|
||||
if (!confirm('¿Enviar mensaje de prueba al canal configurado?')) return;
|
||||
|
||||
const btn = document.querySelector('.btn-success');
|
||||
const originalText = btn.innerHTML;
|
||||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Enviando...';
|
||||
btn.disabled = true;
|
||||
|
||||
try {
|
||||
const response = await fetch('/telegram/api/welcome/send_test.php', {
|
||||
method: 'POST'
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('Mensaje de prueba enviado con éxito a Telegram!');
|
||||
} else {
|
||||
alert('Error: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert('Error de conexión');
|
||||
} finally {
|
||||
btn.innerHTML = originalText;
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
if (event.target == document.getElementById('galleryModal')) {
|
||||
closeGallery();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user