UNPKG

skailan-conversations

Version:

Servicio de conversaciones y mensajería para Skailan

195 lines 8.31 kB
import { Message } from "./domain/entities/Message"; import { Conversation } from "./domain/entities/Conversation"; import { MessagePrismaRepository } from "./infra/database/prisma/MessagePrismaRepository"; import { ConversationPrismaRepository } from "./infra/database/prisma/ConversationPrismaRepository"; import { PrismaClient } from "@prisma/client"; import { v4 as uuidv4 } from "uuid"; export class TelegramWebhookHandler { messageRepository; conversationRepository; constructor() { // Inicializar repositorios con PrismaClient const prisma = new PrismaClient(); this.messageRepository = new MessagePrismaRepository(prisma); this.conversationRepository = new ConversationPrismaRepository(prisma); } async handleWebhook(req, res) { try { console.log("📥 Telegram webhook recibido:", JSON.stringify(req.body, null, 2)); const update = req.body; const organizationId = req.organization?.id; if (!organizationId) { console.error("❌ Organization ID no encontrado en el request"); res.status(400).json({ error: "Organization ID not found" }); return; } if (update.message) { await this.handleMessage(update.message, organizationId); } else if (update.callback_query) { await this.handleCallbackQuery(update.callback_query, organizationId); } // Telegram requiere una respuesta 200 OK res.status(200).json({ ok: true }); } catch (error) { console.error("❌ Error en webhook de Telegram:", error); res.status(500).json({ error: "Internal server error" }); } } async handleMessage(message, organizationId) { if (!message) return; const { from, chat, text, message_id, photo, document, reply_to_message } = message; console.log(`📱 Mensaje recibido de ${from.first_name} (@${from.username}): "${text}"`); console.log(` - Chat ID: ${chat.id}`); console.log(` - Message ID: ${message_id}`); console.log(` - Fecha: ${new Date(message.date * 1000).toLocaleString()}`); try { // Buscar o crear conversación const conversation = await this.findOrCreateConversation(chat.id, from, organizationId); // Determinar tipo de contenido const contentType = this.determineContentType(message); const content = this.extractContent(message); // Crear mensaje en la base de datos const telegramMessage = new Message(uuidv4(), organizationId, conversation.id, "user", // senderType `telegram_user_${from.id}`, // senderId contentType, // type content, // content photo?.[0]?.file_id || document?.file_id || null, // mediaUrl message_id.toString(), // externalMessageId "delivered", // status new Date(message.date * 1000), // timestamp new Date() // createdAt ); // Guardar mensaje const savedMessage = await this.messageRepository.save(telegramMessage); // Actualizar timestamp de última actividad de la conversación await this.updateConversationLastMessage(conversation.id, organizationId); console.log(`✅ Mensaje procesado y guardado: ${savedMessage.id}`); } catch (error) { console.error("❌ Error procesando mensaje de Telegram:", error); } } async handleCallbackQuery(callbackQuery, organizationId) { if (!callbackQuery) return; const { from, data, message } = callbackQuery; console.log(`🔘 Callback query recibido de ${from.first_name}: "${data}"`); console.log(` - Chat ID: ${message.chat.id}`); console.log(` - Message ID: ${message.message_id}`); try { // Buscar conversación const conversation = await this.findConversationByChatId(message.chat.id, organizationId); if (!conversation) { console.error(`❌ Conversación no encontrada para chat ${message.chat.id}`); return; } // Crear mensaje de callback query const callbackMessage = new Message(uuidv4(), organizationId, conversation.id, "user", `telegram_user_${from.id}`, "callback_query", JSON.stringify({ type: "callback_query", data: data, originalMessageId: message.message_id, }), null, // mediaUrl callbackQuery.id, // externalMessageId "delivered", new Date(), new Date()); // Guardar mensaje await this.messageRepository.save(callbackMessage); console.log(`✅ Callback query procesado: ID ${callbackQuery.id}`); } catch (error) { console.error("❌ Error procesando callback query:", error); } } /** * Busca o crea una conversación para el chat */ async findOrCreateConversation(chatId, user, organizationId) { // Buscar conversación existente let conversation = await this.findConversationByChatId(chatId, organizationId); if (!conversation) { // Crear nueva conversación conversation = new Conversation(uuidv4(), organizationId, `telegram_chat_${chatId}`, `telegram_user_${user.id}`, "open", null, // assignedToUserId new Date(), // lastMessageAt new Date(), // createdAt new Date() // updatedAt ); conversation = await this.conversationRepository.save(conversation); console.log(`✅ Nueva conversación creada: ${conversation.id}`); } return conversation; } /** * Busca conversación por chatId */ async findConversationByChatId(chatId, organizationId) { // Implementar búsqueda por metadata // Por ahora retornamos null para crear nueva conversación return null; } /** * Determina el tipo de contenido del mensaje */ determineContentType(message) { if (message?.photo && message.photo.length > 0) { return "image"; } if (message?.document) { return "document"; } if (message?.text) { return "text"; } return "text"; } /** * Extrae el contenido del mensaje */ extractContent(message) { if (message?.text) { return message.text; } if (message?.photo && message.photo.length > 0) { return JSON.stringify({ type: "image", fileId: message.photo[0]?.file_id, width: message.photo[0]?.width, height: message.photo[0]?.height, fileSize: message.photo[0]?.file_size, }); } if (message?.document) { return JSON.stringify({ type: "document", fileId: message.document.file_id, fileName: message.document.file_name, mimeType: message.document.mime_type, fileSize: message.document.file_size, }); } return ""; } /** * Actualiza el timestamp de última actividad de la conversación */ async updateConversationLastMessage(conversationId, organizationId) { try { const conversation = await this.conversationRepository.findById(conversationId, organizationId); if (conversation) { conversation.updatedAt = new Date(); await this.conversationRepository.save(conversation); } } catch (error) { console.error("❌ Error actualizando timestamp de conversación:", error); } } } // Crear una instancia del manejador const telegramWebhookHandler = new TelegramWebhookHandler(); // Exportar la función para usar en Express export const handleTelegramWebhook = (req, res) => { return telegramWebhookHandler.handleWebhook(req, res); }; //# sourceMappingURL=telegram-webhook.js.map