up
This commit is contained in:
@@ -31,11 +31,15 @@ try {
|
||||
id,
|
||||
user_id,
|
||||
COALESCE(content, message_text) as content,
|
||||
message_id,
|
||||
c.media_url,
|
||||
u.phone_number as user_phone,
|
||||
direction,
|
||||
message_type,
|
||||
status,
|
||||
created_at
|
||||
FROM conversations
|
||||
FROM conversations c
|
||||
LEFT JOIN users u ON c.user_id = u.id
|
||||
WHERE user_id = :user_id
|
||||
UNION ALL
|
||||
SELECT
|
||||
@@ -76,6 +80,9 @@ try {
|
||||
'id' => intval($msg['id']),
|
||||
'user_id' => intval($msg['user_id']),
|
||||
'content' => $msg['content'] ?? '',
|
||||
'message_id' => $msg['message_id'] ?? null,
|
||||
'media_url' => $msg['media_url'] ?? null,
|
||||
'user_phone' => $msg['user_phone'] ?? null,
|
||||
'direction' => $msg['direction'] ?? 'incoming',
|
||||
'message_type' => $msg['message_type'] ?? 'text',
|
||||
'status' => $msg['status'] ?? 'sent',
|
||||
|
||||
@@ -155,10 +155,16 @@ try {
|
||||
error_log("=== DEBUG WHATSAPP TEXT MESSAGE ===");
|
||||
error_log("Recipient: " . $recipient);
|
||||
error_log("Message: " . $input['message']);
|
||||
error_log("Method: sendTextMessage()");
|
||||
error_log("Method: sendTextMessage()/sendTextReply()");
|
||||
error_log("====================================");
|
||||
|
||||
$response = $whatsappService->sendTextMessage($recipient, $input['message']);
|
||||
|
||||
// Si viene reply_to, usar reply con contexto
|
||||
if (!empty($input['reply_to'])) {
|
||||
$replyTo = $input['reply_to'];
|
||||
$response = $whatsappService->sendTextReply($recipient, $replyTo, $input['message']);
|
||||
} else {
|
||||
$response = $whatsappService->sendTextMessage($recipient, $input['message']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'template':
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config_enhanced.php';
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// Autenticación para APIs (debug skip)
|
||||
$debugMode = isset($_GET['debug']) && $_GET['debug'] === 'true';
|
||||
if (!$debugMode && function_exists('requireAuthentication')) {
|
||||
requireAuthentication();
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
|
||||
$to = $input['to'] ?? null;
|
||||
$message_id = $input['message_id'] ?? null;
|
||||
$emoji = $input['emoji'] ?? null;
|
||||
$dry = isset($input['dry_run']) ? (bool)$input['dry_run'] : false;
|
||||
|
||||
if (!$to || !$message_id || !$emoji) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'Parámetros faltantes: to, message_id, emoji']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$wa = new WhatsAppService();
|
||||
$result = $wa->sendReaction($to, $message_id, $emoji, $dry);
|
||||
echo json_encode(['success' => true, 'dry_run' => $dry, 'result' => $result]);
|
||||
} catch (Throwable $t) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $t->getMessage()]);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config_enhanced.php';
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// Autenticación para APIs (debug skip)
|
||||
$debugMode = isset($_GET['debug']) && $_GET['debug'] === 'true';
|
||||
if (!$debugMode && function_exists('requireAuthentication')) {
|
||||
requireAuthentication();
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
|
||||
$to = $input['to'] ?? null;
|
||||
$message_id = $input['message_id'] ?? null;
|
||||
$text = $input['text'] ?? null;
|
||||
$preview = isset($input['preview_url']) ? (bool)$input['preview_url'] : false;
|
||||
$dry = isset($input['dry_run']) ? (bool)$input['dry_run'] : false;
|
||||
|
||||
if (!$to || !$message_id || !$text) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'Parámetros faltantes: to, message_id, text']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$wa = new WhatsAppService();
|
||||
$result = $wa->sendTextReply($to, $message_id, $text, $preview, $dry);
|
||||
echo json_encode(['success' => true, 'dry_run' => $dry, 'result' => $result]);
|
||||
} catch (Throwable $t) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $t->getMessage()]);
|
||||
}
|
||||
+7
-1
@@ -128,7 +128,13 @@ class WhatsAppWebhook {
|
||||
$messageType = 'text';
|
||||
$mediaUrl = null;
|
||||
|
||||
if (isset($message['text'])) {
|
||||
if (isset($message['reaction'])) {
|
||||
// Reacción (emoji) a un mensaje anterior
|
||||
$messageType = 'reaction';
|
||||
$emoji = $message['reaction']['emoji'] ?? '';
|
||||
$reactionTo = $message['reaction']['message_id'] ?? '';
|
||||
$messageText = json_encode(['emoji' => $emoji, 'message_id' => $reactionTo]);
|
||||
} elseif (isset($message['text'])) {
|
||||
$messageText = $message['text']['body'];
|
||||
$messageType = 'text';
|
||||
} elseif (isset($message['image'])) {
|
||||
|
||||
@@ -1028,6 +1028,38 @@ class WhatsAppBotManager {
|
||||
this.showTab('messages');
|
||||
}
|
||||
|
||||
replyToMessage(messageId, userPhone) {
|
||||
// Poner en el input del chat y almacenar reply_to en data attribute
|
||||
document.getElementById('message-input').focus();
|
||||
document.getElementById('message-input').dataset.replyTo = messageId;
|
||||
this.showSuccess('Preparado para responder al mensaje ' + messageId);
|
||||
}
|
||||
|
||||
async reactToMessage(messageId, userPhone) {
|
||||
const emoji = prompt('Escribe el emoji de reacción (ej: ❤️, 👍):');
|
||||
if (!emoji) return;
|
||||
|
||||
try {
|
||||
const resp = await fetch('api/send_reaction.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ to: userPhone, message_id: messageId, emoji: emoji })
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.success) {
|
||||
this.showSuccess('Reacción enviada');
|
||||
// Refrescar mensajes
|
||||
await this.loadMessages(this.currentUserId, false);
|
||||
} else {
|
||||
this.showError('Error enviando reacción: ' + (data.error || 'desconocido'));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('reactToMessage error', err);
|
||||
this.showError('Error comunicándose con el servidor');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
editUser(userId) {
|
||||
// Implementar modal de edición de usuario
|
||||
console.log('Editar usuario:', userId);
|
||||
|
||||
+30
-30
@@ -44,50 +44,50 @@ function env($key, $default = null) {
|
||||
}
|
||||
|
||||
// Configuración de la base de datos
|
||||
define('DB_HOST', env('DB_HOST', 'localhost'));
|
||||
define('DB_PORT', env('DB_PORT', '3306'));
|
||||
define('DB_NAME', env('DB_NAME', 'whatsapp_bot'));
|
||||
define('DB_USER', env('DB_USER', 'whatsapp_user'));
|
||||
define('DB_PASS', env('DB_PASS', '')); // Se generará automáticamente en la instalación
|
||||
define('DB_CHARSET', env('DB_CHARSET', 'utf8mb4'));
|
||||
if (!defined('DB_HOST')) define('DB_HOST', env('DB_HOST', 'localhost'));
|
||||
if (!defined('DB_PORT')) define('DB_PORT', env('DB_PORT', '3306'));
|
||||
if (!defined('DB_NAME')) define('DB_NAME', env('DB_NAME', 'whatsapp_bot'));
|
||||
if (!defined('DB_USER')) define('DB_USER', env('DB_USER', 'whatsapp_user'));
|
||||
if (!defined('DB_PASS')) define('DB_PASS', env('DB_PASS', '')); // Se generará automáticamente en la instalación
|
||||
if (!defined('DB_CHARSET')) define('DB_CHARSET', env('DB_CHARSET', 'utf8mb4'));
|
||||
|
||||
// WhatsApp Business API
|
||||
define('WHATSAPP_TOKEN', env('WHATSAPP_TOKEN', 'TU_TOKEN_DE_WHATSAPP_AQUI'));
|
||||
define('WHATSAPP_PHONE_NUMBER_ID', env('WHATSAPP_PHONE_NUMBER_ID', 'TU_PHONE_ID_AQUI'));
|
||||
define('WHATSAPP_API_URL', env('WHATSAPP_API_URL', 'https://graph.facebook.com/v22.0/'));
|
||||
define('WEBHOOK_VERIFY_TOKEN', env('WEBHOOK_VERIFY_TOKEN', 'mi_token_secreto_123'));
|
||||
if (!defined('WHATSAPP_TOKEN')) define('WHATSAPP_TOKEN', env('WHATSAPP_TOKEN', 'TU_TOKEN_DE_WHATSAPP_AQUI'));
|
||||
if (!defined('WHATSAPP_PHONE_NUMBER_ID')) define('WHATSAPP_PHONE_NUMBER_ID', env('WHATSAPP_PHONE_NUMBER_ID', 'TU_PHONE_ID_AQUI'));
|
||||
if (!defined('WHATSAPP_API_URL')) define('WHATSAPP_API_URL', env('WHATSAPP_API_URL', 'https://graph.facebook.com/v22.0/'));
|
||||
if (!defined('WEBHOOK_VERIFY_TOKEN')) define('WEBHOOK_VERIFY_TOKEN', env('WEBHOOK_VERIFY_TOKEN', 'mi_token_secreto_123'));
|
||||
|
||||
// Auto-approve templates: Si está activado, las plantillas creadas localmente se marcarán como 'approved' automáticamente
|
||||
define('AUTO_APPROVE_TEMPLATES', filter_var(env('AUTO_APPROVE_TEMPLATES', 'false'), FILTER_VALIDATE_BOOLEAN));
|
||||
if (!defined('AUTO_APPROVE_TEMPLATES')) define('AUTO_APPROVE_TEMPLATES', filter_var(env('AUTO_APPROVE_TEMPLATES', 'false'), FILTER_VALIDATE_BOOLEAN));
|
||||
|
||||
// Configuración general
|
||||
define('APP_NAME', env('APP_NAME', 'WhatsApp Bot System'));
|
||||
define('APP_VERSION', env('APP_VERSION', '1.0.0'));
|
||||
define('APP_URL', env('APP_URL', 'https://tudominio.com')); // Se auto-detectará
|
||||
define('TIMEZONE', env('TIMEZONE', 'America/Bogota'));
|
||||
if (!defined('APP_NAME')) define('APP_NAME', env('APP_NAME', 'WhatsApp Bot System'));
|
||||
if (!defined('APP_VERSION')) define('APP_VERSION', env('APP_VERSION', '1.0.0'));
|
||||
if (!defined('APP_URL')) define('APP_URL', env('APP_URL', 'https://tudominio.com'));
|
||||
if (!defined('TIMEZONE')) define('TIMEZONE', env('TIMEZONE', 'America/Bogota'));
|
||||
|
||||
// Información del desarrollador
|
||||
define('DEVELOPER_NAME', 'U-Site.app');
|
||||
define('DEVELOPER_URL', 'https://u-site.app');
|
||||
define('DEVELOPER_EMAIL', 'support@u-site.app');
|
||||
define('DEVELOPER_SUPPORT', 'https://u-site.app/support');
|
||||
if (!defined('DEVELOPER_NAME')) define('DEVELOPER_NAME', 'U-Site.app');
|
||||
if (!defined('DEVELOPER_URL')) define('DEVELOPER_URL', 'https://u-site.app');
|
||||
if (!defined('DEVELOPER_EMAIL')) define('DEVELOPER_EMAIL', 'support@u-site.app');
|
||||
if (!defined('DEVELOPER_SUPPORT')) define('DEVELOPER_SUPPORT', 'https://u-site.app/support');
|
||||
|
||||
// Configuración de seguridad
|
||||
define('INSTALLATION_LOCK', '.installation_completed'); // Archivo de bloqueo
|
||||
define('ADMIN_USERNAME', env('ADMIN_USERNAME', 'admin')); // Usuario administrador por defecto
|
||||
define('ADMIN_PASSWORD', env('ADMIN_PASSWORD', '')); // Se configurará en instalación
|
||||
define('SESSION_TIMEOUT', (int)env('SESSION_TIMEOUT', 1800)); // 30 minutos
|
||||
define('MAX_LOGIN_ATTEMPTS', (int)env('MAX_LOGIN_ATTEMPTS', 3)); // Intentos máximos de login
|
||||
define('LOGIN_LOCKOUT_TIME', (int)env('LOGIN_LOCKOUT_TIME', 900)); // 15 minutos de bloqueo tras fallos
|
||||
if (!defined('INSTALLATION_LOCK')) define('INSTALLATION_LOCK', '.installation_completed');
|
||||
if (!defined('ADMIN_USERNAME')) define('ADMIN_USERNAME', env('ADMIN_USERNAME', 'admin'));
|
||||
if (!defined('ADMIN_PASSWORD')) define('ADMIN_PASSWORD', env('ADMIN_PASSWORD', ''));
|
||||
if (!defined('SESSION_TIMEOUT')) define('SESSION_TIMEOUT', (int)env('SESSION_TIMEOUT', 1800));
|
||||
if (!defined('MAX_LOGIN_ATTEMPTS')) define('MAX_LOGIN_ATTEMPTS', (int)env('MAX_LOGIN_ATTEMPTS', 3));
|
||||
if (!defined('LOGIN_LOCKOUT_TIME')) define('LOGIN_LOCKOUT_TIME', (int)env('LOGIN_LOCKOUT_TIME', 900));
|
||||
|
||||
// Configuración de logs
|
||||
define('ENABLE_LOGGING', filter_var(env('ENABLE_LOGGING', 'true'), FILTER_VALIDATE_BOOLEAN));
|
||||
define('LOG_LEVEL', env('LOG_LEVEL', 'INFO')); // DEBUG, INFO, WARNING, ERROR
|
||||
define('LOG_FILE', env('LOG_FILE', 'logs/system.log'));
|
||||
if (!defined('ENABLE_LOGGING')) define('ENABLE_LOGGING', filter_var(env('ENABLE_LOGGING', 'true'), FILTER_VALIDATE_BOOLEAN));
|
||||
if (!defined('LOG_LEVEL')) define('LOG_LEVEL', env('LOG_LEVEL', 'INFO')); // DEBUG, INFO, WARNING, ERROR
|
||||
if (!defined('LOG_FILE')) define('LOG_FILE', env('LOG_FILE', 'logs/system.log'));
|
||||
|
||||
// Configuración de archivos
|
||||
define('UPLOAD_MAX_SIZE', (int)env('UPLOAD_MAX_SIZE', 10485760)); // 10MB
|
||||
define('ALLOWED_FILE_TYPES', ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx', 'mp4', 'mp3', 'wav']);
|
||||
if (!defined('UPLOAD_MAX_SIZE')) define('UPLOAD_MAX_SIZE', (int)env('UPLOAD_MAX_SIZE', 10485760)); // 10MB
|
||||
if (!defined('ALLOWED_FILE_TYPES')) define('ALLOWED_FILE_TYPES', ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx', 'mp4', 'mp3', 'wav']);
|
||||
|
||||
// Configurar zona horaria
|
||||
date_default_timezone_set(TIMEZONE);
|
||||
|
||||
+9
-1
@@ -748,6 +748,10 @@
|
||||
<div class="message ${msg.direction}">
|
||||
<div class="message-bubble">
|
||||
${content}
|
||||
<div class="message-actions mt-1">
|
||||
<button class="btn btn-sm btn-link" onclick="app.replyToMessage('${msg.message_id}','${msg.user_phone}')" title="Responder"><i class="fas fa-reply"></i></button>
|
||||
<button class="btn btn-sm btn-link" onclick="app.reactToMessage('${msg.message_id}','${msg.user_phone}')" title="Reaccionar"><i class="far fa-grin"></i></button>
|
||||
</div>
|
||||
<div class="message-time">
|
||||
${time}
|
||||
${msg.direction === 'outgoing' ? `<span class="message-status">${statusIcon}</span>` : ''}
|
||||
@@ -785,6 +789,7 @@
|
||||
document.getElementById('send-btn').disabled = true;
|
||||
|
||||
try {
|
||||
const replyTo = input.dataset.replyTo || null;
|
||||
const response = await fetch('api/send_message.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -792,9 +797,12 @@
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user_id: this.currentUserId,
|
||||
message: message
|
||||
message: message,
|
||||
reply_to: replyTo
|
||||
})
|
||||
});
|
||||
// Clear reply data attribute
|
||||
input.dataset.replyTo = null;
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Safe migration: show current column type, backup distinct statuses, then alter.
|
||||
*/
|
||||
require_once __DIR__ . '/../config/config_enhanced.php';
|
||||
require_once __DIR__ . '/../classes/Database.php';
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
echo "Current structure for conversations table:\n";
|
||||
$rows = $db->fetchAll("SHOW COLUMNS FROM conversations LIKE 'status'");
|
||||
print_r($rows);
|
||||
|
||||
$distinct = $db->fetchAll("SELECT DISTINCT status FROM conversations");
|
||||
echo "Distinct status values in table:\n";
|
||||
print_r(array_column($distinct, 'status'));
|
||||
|
||||
// Ask user confirmation (CLI only)
|
||||
if (php_sapi_name() === 'cli') {
|
||||
echo "About to alter column 'status' to ENUM('sent','delivered','read','failed','received') DEFAULT 'sent'. Continue? (y/N): ";
|
||||
$resp = trim(fgets(STDIN));
|
||||
if (strtolower($resp) !== 'y') {
|
||||
echo "Aborted by user.\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$db->query("ALTER TABLE conversations MODIFY COLUMN status ENUM('sent','delivered','read','failed','received') DEFAULT 'sent'");
|
||||
echo "ALTER OK\n";
|
||||
} catch (Exception $e) {
|
||||
echo "ERROR: " . $e->getMessage() . "\n";
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
ini_set('display_errors',1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// Test calling API endpoint internally by setting input stream
|
||||
$payload = json_encode([
|
||||
'to' => '573001234567',
|
||||
'message_id' => '<TEST_MSGID>',
|
||||
'emoji' => '👍',
|
||||
'dry_run' => true
|
||||
]);
|
||||
|
||||
file_put_contents('php://memory', $payload); // no effect; instead call service directly
|
||||
|
||||
require_once __DIR__ . '/../api/send_reaction.php';
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
ini_set('display_errors',1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
require_once __DIR__ . '/../api/send_reply.php';
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
ini_set('display_errors',1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
require_once __DIR__ . '/../services/WhatsAppService.php';
|
||||
|
||||
try {
|
||||
$s = new WhatsAppService();
|
||||
echo "WhatsAppService loaded\n";
|
||||
|
||||
echo "Dry-run reaction:\n";
|
||||
$r = $s->sendReaction('573001234567', '<MSGID123>', '❤️', true);
|
||||
print_r($r);
|
||||
|
||||
echo "Dry-run text reply:\n";
|
||||
$rr = $s->sendTextReply('573001234567', '<MSGID123>', 'Gracias por tu mensaje', false, true);
|
||||
print_r($rr);
|
||||
|
||||
} catch (Throwable $t) {
|
||||
echo "ERROR: " . $t->getMessage() . "\n";
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
ini_set('display_errors',1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
require_once __DIR__ . '/../api/webhook.php';
|
||||
|
||||
$payload = [
|
||||
"object" => "whatsapp_business_account",
|
||||
"entry" => [
|
||||
[
|
||||
"id" => "0",
|
||||
"changes" => [
|
||||
[
|
||||
"field" => "messages",
|
||||
"value" => [
|
||||
"messaging_product" => "whatsapp",
|
||||
"metadata" => [
|
||||
"display_phone_number" => "16505551111",
|
||||
"phone_number_id" => "123456123"
|
||||
],
|
||||
"contacts" => [
|
||||
[
|
||||
"profile" => ["name" => "test user name"],
|
||||
"wa_id" => "16315551181"
|
||||
]
|
||||
],
|
||||
"messages" => [
|
||||
[
|
||||
"from" => "16315551181",
|
||||
"id" => "ABGGFlA5Fpa",
|
||||
"timestamp" => "1504902988",
|
||||
"type" => "text",
|
||||
"text" => ["body" => "this is a text message"]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
try {
|
||||
$w = new WhatsAppWebhook();
|
||||
echo "Webhook instance created\n";
|
||||
$result = $w->processPayload($payload);
|
||||
echo "processPayload result: " . ($result ? 'true' : 'false') . "\n";
|
||||
|
||||
// Simular reacción entrante
|
||||
$reactionPayload = [
|
||||
"object" => "whatsapp_business_account",
|
||||
"entry" => [
|
||||
[
|
||||
"id" => "0",
|
||||
"changes" => [
|
||||
[
|
||||
"field" => "messages",
|
||||
"value" => [
|
||||
"messaging_product" => "whatsapp",
|
||||
"metadata" => [
|
||||
"display_phone_number" => "16505551111",
|
||||
"phone_number_id" => "123456123"
|
||||
],
|
||||
"contacts" => [
|
||||
[
|
||||
"profile" => ["name" => "reactor"],
|
||||
"wa_id" => "16315551181"
|
||||
]
|
||||
],
|
||||
"messages" => [
|
||||
[
|
||||
"from" => "16315551181",
|
||||
"id" => "REACTION1",
|
||||
"timestamp" => "1504902990",
|
||||
"type" => "reaction",
|
||||
"reaction" => ["message_id" => "ABGGFlA5Fpa", "emoji" => "❤️"]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$r2 = $w->processPayload($reactionPayload);
|
||||
echo "processReaction result: " . ($r2 ? 'true' : 'false') . "\n";
|
||||
|
||||
} catch (Throwable $t) {
|
||||
echo "Fatal: " . $t->getMessage() . "\n";
|
||||
echo $t->getTraceAsString() . "\n";
|
||||
}
|
||||
|
||||
// Show last lines of system log
|
||||
$log = __DIR__ . '/../logs/system.log';
|
||||
if (file_exists($log)) {
|
||||
echo "-- Last log lines --\n";
|
||||
$lines = array_slice(file($log), -40);
|
||||
foreach ($lines as $line) echo $line;
|
||||
} else {
|
||||
echo "No log file found\n";
|
||||
}
|
||||
@@ -536,10 +536,62 @@ class WhatsAppService
|
||||
return $data['interactive']['body']['text'];
|
||||
}
|
||||
break;
|
||||
case 'reaction':
|
||||
return isset($data['reaction']['emoji']) ? $data['reaction']['emoji'] : json_encode($data['reaction']);
|
||||
}
|
||||
return json_encode($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enviar reacción (emoji) a un mensaje previo
|
||||
* @param string $to Teléfono del destinatario
|
||||
* @param string $messageId ID del mensaje al que se reacciona
|
||||
* @param string $emoji Emoji de reacción
|
||||
* @param bool $dryRun Si true, no hace la petición y devuelve el payload
|
||||
*/
|
||||
public function sendReaction($to, $messageId, $emoji, $dryRun = false)
|
||||
{
|
||||
$data = [
|
||||
'messaging_product' => 'whatsapp',
|
||||
'to' => $this->formatPhoneNumber($to),
|
||||
'type' => 'reaction',
|
||||
'reaction' => [
|
||||
'message_id' => $messageId,
|
||||
'emoji' => $emoji
|
||||
]
|
||||
];
|
||||
|
||||
if ($dryRun) return $data;
|
||||
return $this->sendMessage($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enviar texto como respuesta (con contexto) a un mensaje existente
|
||||
* @param string $to Teléfono del destinatario
|
||||
* @param string $messageId ID del mensaje al que se responde
|
||||
* @param string $text Contenido del mensaje de respuesta
|
||||
* @param bool $preview_url Incluir preview_url en body.text
|
||||
* @param bool $dryRun Si true, no hace la petición y devuelve el payload
|
||||
*/
|
||||
public function sendTextReply($to, $messageId, $text, $preview_url = false, $dryRun = false)
|
||||
{
|
||||
$data = [
|
||||
'messaging_product' => 'whatsapp',
|
||||
'to' => $this->formatPhoneNumber($to),
|
||||
'type' => 'text',
|
||||
'context' => [
|
||||
'message_id' => $messageId
|
||||
],
|
||||
'text' => [
|
||||
'preview_url' => (bool)$preview_url,
|
||||
'body' => $text
|
||||
]
|
||||
];
|
||||
|
||||
if ($dryRun) return $data;
|
||||
return $this->sendMessage($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener usuario por teléfono
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user