From ec614c2a89d6de8288fbaf8e8831f92da355ec24 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Fri, 3 Jul 2026 00:53:16 -0500 Subject: [PATCH] feat(chat-turnero): backend APIs for media upload, reactions, and template messages - chat_upload_media.php: multipart upload to WhatsApp Media API, sends image/video/audio/document - chat_react.php: sends emoji reaction to a message via WhatsApp, updates reaction_emoji in DB - chat_send_message.php: extended to support type=template with lang+params Co-Authored-By: Claude Sonnet 4.6 --- modules/turnero/api/chat_react.php | 47 ++++++++++++++++ modules/turnero/api/chat_send_message.php | 57 +++++++------------ modules/turnero/api/chat_upload_media.php | 68 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 36 deletions(-) create mode 100644 modules/turnero/api/chat_react.php create mode 100644 modules/turnero/api/chat_upload_media.php diff --git a/modules/turnero/api/chat_react.php b/modules/turnero/api/chat_react.php new file mode 100644 index 0000000..cf862cd --- /dev/null +++ b/modules/turnero/api/chat_react.php @@ -0,0 +1,47 @@ +false,'error'=>'Método no permitido']); exit; } + +$input = json_decode(file_get_contents('php://input'), true) ?? []; +$messageId = trim($input['message_id'] ?? ''); +$userId = intval($input['user_id'] ?? 0); +$emoji = trim($input['emoji'] ?? ''); + +if (!$messageId || !$userId || !$emoji) { + http_response_code(400); + echo json_encode(['success'=>false,'error'=>'message_id, user_id y emoji son requeridos']); + exit; +} + +try { + $db = Database::getInstance(); + $user = $db->fetch("SELECT phone_number FROM users WHERE id = ?", [$userId]); + if (!$user) { http_response_code(404); echo json_encode(['success'=>false,'error'=>'Usuario no encontrado']); exit; } + + $phoneId = getConfigFromDB('whatsapp_phone_number_id_turnero', ''); + if (!$phoneId) { http_response_code(503); echo json_encode(['success'=>false,'error'=>'Número turnero no configurado']); exit; } + + $wa = new WhatsAppService('turnero'); + $resp = $wa->sendReaction($user['phone_number'], $messageId, $emoji, false); + + // Guardar reacción en el mensaje + $db->query( + "UPDATE messages SET reaction_emoji = ?, reaction_to_message_id = ? WHERE whatsapp_message_id = ?", + [$emoji, $messageId, $messageId] + ); + + echo json_encode(['success' => true, 'response' => $resp]); + +} catch (Exception $e) { + error_log('chat_react: ' . $e->getMessage()); + http_response_code(500); + echo json_encode(['success' => false, 'error' => $e->getMessage()]); +} diff --git a/modules/turnero/api/chat_send_message.php b/modules/turnero/api/chat_send_message.php index f9beb05..cd57dec 100644 --- a/modules/turnero/api/chat_send_message.php +++ b/modules/turnero/api/chat_send_message.php @@ -1,61 +1,46 @@ false, 'error' => 'Método no permitido']); - exit; -} +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['success'=>false,'error'=>'Método no permitido']); exit; } try { - $input = json_decode(file_get_contents('php://input'), true); - if (!$input) { - $input = $_POST; - } + $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; - $userId = intval($input['user_id'] ?? 0); - $message = trim($input['message'] ?? ''); + $userId = intval($input['user_id'] ?? 0); + $type = $input['type'] ?? 'text'; + $message = trim($input['message'] ?? ''); + $template = trim($input['template'] ?? ''); + $lang = trim($input['lang'] ?? 'es_CO'); + $params = $input['params'] ?? []; - if (!$userId || $message === '') { - http_response_code(400); - echo json_encode(['success' => false, 'error' => 'user_id y message son requeridos']); - exit; + if (!$userId || ($type === 'text' && $message === '') || ($type === 'template' && $template === '')) { + http_response_code(400); echo json_encode(['success'=>false,'error'=>'Parámetros insuficientes']); exit; } $db = Database::getInstance(); $user = $db->fetch("SELECT phone_number, name FROM users WHERE id = :id", ['id' => $userId]); + if (!$user) { http_response_code(404); echo json_encode(['success'=>false,'error'=>'Usuario no encontrado']); exit; } - if (!$user) { - http_response_code(404); - echo json_encode(['success' => false, 'error' => 'Usuario no encontrado']); - exit; - } - - // Verificar que el número turnero esté configurado $turneroPhoneId = getConfigFromDB('whatsapp_phone_number_id_turnero', ''); - if (empty($turneroPhoneId)) { - http_response_code(503); - echo json_encode(['success' => false, 'error' => 'El número de WhatsApp del turnero no está configurado']); - exit; - } + if (empty($turneroPhoneId)) { http_response_code(503); echo json_encode(['success'=>false,'error'=>'Número turnero no configurado']); exit; } $operatorId = $_SESSION['admin_id'] ?? $_SESSION['user_id'] ?? null; + $wa = new WhatsAppService('turnero'); - $wa = new WhatsAppService('turnero'); - $response = $wa->sendTextMessage( - $user['phone_number'], - $message, - $operatorId ? ['operator_id' => $operatorId, 'canal' => 'turnero'] : ['canal' => 'turnero'] - ); + if ($type === 'template') { + $response = $wa->sendTemplateMessage($user['phone_number'], $template, $lang, $params); + } else { + $extra = ['canal' => 'turnero']; + if ($operatorId) $extra['operator_id'] = $operatorId; + $response = $wa->sendTextMessage($user['phone_number'], $message, $extra); + } echo json_encode(['success' => true, 'whatsapp_response' => $response]); diff --git a/modules/turnero/api/chat_upload_media.php b/modules/turnero/api/chat_upload_media.php new file mode 100644 index 0000000..f14021a --- /dev/null +++ b/modules/turnero/api/chat_upload_media.php @@ -0,0 +1,68 @@ +false,'error'=>'Método no permitido']); exit; } + +function tmErr($msg, $code=400) { http_response_code($code); echo json_encode(['success'=>false,'error'=>$msg]); exit; } + +$userId = intval($_POST['user_id'] ?? 0); +if (!$userId) tmErr('user_id requerido'); +if (empty($_FILES['file'])) tmErr('Archivo requerido'); + +$file = $_FILES['file']; +if ($file['error'] !== UPLOAD_ERR_OK) tmErr('Error al subir archivo: código ' . $file['error']); + +$maxBytes = 64 * 1024 * 1024; // 64 MB +if ($file['size'] > $maxBytes) tmErr('El archivo supera el límite de 64 MB'); + +$mime = mime_content_type($file['tmp_name']) ?: $file['type']; +$caption = trim($_POST['caption'] ?? ''); +$isVoice = !empty($_POST['is_voice']); + +// Determinar tipo de media +if (str_starts_with($mime, 'image/')) $mediaType = 'image'; +elseif (str_starts_with($mime, 'video/')) $mediaType = 'video'; +elseif (str_starts_with($mime, 'audio/')) $mediaType = 'audio'; +else $mediaType = 'document'; + +try { + $db = Database::getInstance(); + $user = $db->fetch("SELECT phone_number FROM users WHERE id = ?", [$userId]); + if (!$user) tmErr('Usuario no encontrado', 404); + + $phoneId = getConfigFromDB('whatsapp_phone_number_id_turnero', ''); + if (!$phoneId) tmErr('Número turnero no configurado', 503); + + $wa = new WhatsAppService('turnero'); + + // Subir a WhatsApp Media API + $mediaId = $wa->uploadMedia($file['tmp_name'], $mime); + if (!$mediaId) tmErr('No se pudo subir el archivo a WhatsApp', 502); + + $opId = $_SESSION['admin_id'] ?? $_SESSION['user_id'] ?? null; + $extra = ['canal' => 'turnero']; + if ($opId) $extra['operator_id'] = $opId; + + $resp = $wa->sendMediaById( + $user['phone_number'], + $mediaId, + $mediaType, + $caption ?: null, + $file['name'], + false, + $isVoice + ); + + echo json_encode(['success' => true, 'media_type' => $mediaType, 'response' => $resp]); + +} catch (Exception $e) { + error_log('chat_upload_media: ' . $e->getMessage()); + tmErr($e->getMessage(), 500); +}