UNPKG

skailan-conversations

Version:

Servicio de conversaciones y mensajería para Skailan

348 lines 13.7 kB
import { TelegramChannelService } from "../../domain/services/TelegramChannelService"; import { ChannelPrismaRepository } from "../../infra/database/prisma/ChannelPrismaRepository"; import { ConversationPrismaRepository } from "../../infra/database/prisma/ConversationPrismaRepository"; import { MessagePrismaRepository } from "../../infra/database/prisma/MessagePrismaRepository"; import { TelegramService } from "../../domain/services/TelegramService"; import { PrismaClient } from "@prisma/client"; export class UnifiedWebhookController { channelService; conversationRepository; messageRepository; channelRepository; constructor() { const prisma = new PrismaClient(); this.conversationRepository = new ConversationPrismaRepository(prisma); this.messageRepository = new MessagePrismaRepository(prisma); this.channelRepository = new ChannelPrismaRepository(prisma); // Crear instancia de TelegramService con un token por defecto const telegramService = new TelegramService(process.env.TELEGRAM_BOT_TOKEN || "default_token"); this.channelService = new TelegramChannelService(telegramService, this.messageRepository, this.conversationRepository, this.channelRepository); } /** * Verifica webhooks para diferentes plataformas */ async verifyWebhook(req, res) { try { const { platform } = req.params; const { mode, challenge, verifyToken } = req.query; if (mode === 'subscribe' && challenge) { // Verificar el token si es necesario if (verifyToken) { // Aquí puedes agregar lógica de verificación del token console.log(`✅ Webhook verificado para ${platform}`); } res.status(200).send(challenge); return; } res.status(400).json({ error: 'Invalid verification request' }); } catch (error) { console.error(`❌ Error verificando webhook de ${req.params.platform}:`, error); res.status(500).json({ error: 'Internal server error' }); } } /** * Maneja webhooks unificados para múltiples plataformas */ async handleWebhook(req, res) { try { const { platform } = req.params; const organizationId = req.organization?.id; if (!organizationId) { res.status(400).json({ error: "Organization ID not found" }); return; } if (!platform) { res.status(400).json({ error: "Platform parameter is required" }); return; } // Determinar el tipo de canal basado en la plataforma const channelType = this.getChannelTypeFromPlatform(platform); if (!channelType) { res.status(400).json({ error: `Unsupported platform: ${platform}` }); return; } // Obtener canales de la organización const channels = await this.channelRepository.findAll(organizationId); // Filtrar canales del tipo específico const platformChannels = channels.filter((channel) => channel.type === channelType); if (platformChannels.length === 0) { res.status(400).json({ error: `No ${platform} channels configured for this organization`, }); return; } // Procesar el webhook según la plataforma const result = await this.processWebhookByPlatform(platform, req.body, organizationId, platformChannels); if (result.success) { res.json({ success: true, message: "Webhook processed successfully", data: result.data, }); } else { res.status(400).json({ success: false, error: result.error, }); } } catch (error) { console.error(`❌ Error procesando webhook de ${req.params.platform}:`, error); res.status(500).json({ success: false, error: "Internal server error", }); } } /** * Procesa webhooks específicos por plataforma */ async processWebhookByPlatform(platform, webhookData, organizationId, channels) { try { switch (platform.toLowerCase()) { case "telegram": return await this.processTelegramWebhook(webhookData, organizationId, channels); case "whatsapp": return await this.processWhatsAppWebhook(webhookData, organizationId, channels); case "facebook": return await this.processFacebookWebhook(webhookData, organizationId, channels); default: return { success: false, error: `Unsupported platform: ${platform}`, }; } } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Unknown error", }; } } /** * Procesa webhook de Telegram */ async processTelegramWebhook(webhookData, organizationId, channels) { try { // Validar que es una actualización válida de Telegram if (!webhookData.update_id || !webhookData.message) { return { success: false, error: "Invalid Telegram webhook data", }; } // Obtener el canal de Telegram (asumimos que hay uno por organización) const telegramChannel = channels.find((channel) => channel.type === "telegram"); if (!telegramChannel) { return { success: false, error: "Telegram channel not found", }; } // Procesar la actualización usando el servicio de Telegram const result = await this.channelService.processIncomingMessage(telegramChannel.id, organizationId, { id: webhookData.update_id.toString(), from: webhookData.message.from.id.toString(), to: webhookData.message.chat.id.toString(), type: "text", content: webhookData.message.text || "", timestamp: new Date(webhookData.message.date * 1000), metadata: { platform: "telegram", }, }); return { success: true, data: result, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Error processing Telegram webhook", }; } } /** * Procesa webhook de WhatsApp */ async processWhatsAppWebhook(webhookData, organizationId, channels) { try { // Validar datos de WhatsApp if (!webhookData.entry || !webhookData.entry[0]?.changes) { return { success: false, error: "Invalid WhatsApp webhook data", }; } // Obtener el canal de WhatsApp const whatsappChannel = channels.find((channel) => channel.type === "whatsapp"); if (!whatsappChannel) { return { success: false, error: "WhatsApp channel not found", }; } // Procesar la actualización const result = await this.channelService.processIncomingMessage(whatsappChannel.id, organizationId, { id: webhookData.entry[0].changes[0].value.messages?.[0]?.id || "unknown", from: webhookData.entry[0].changes[0].value.messages?.[0]?.from || "unknown", to: whatsappChannel.id, type: "text", content: webhookData.entry[0].changes[0].value.messages?.[0]?.text?.body || "", timestamp: new Date(), metadata: { platform: "whatsapp", }, }); return { success: true, data: result, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Error processing WhatsApp webhook", }; } } /** * Procesa webhook de Facebook */ async processFacebookWebhook(webhookData, organizationId, channels) { try { // Validar datos de Facebook if (!webhookData.object || !webhookData.entry) { return { success: false, error: "Invalid Facebook webhook data", }; } // Obtener el canal de Facebook const facebookChannel = channels.find((channel) => channel.type === "facebook"); if (!facebookChannel) { return { success: false, error: "Facebook channel not found", }; } // Procesar la actualización const result = await this.channelService.processIncomingMessage(facebookChannel.id, organizationId, { id: webhookData.entry[0].messaging?.[0]?.message?.mid || "unknown", from: webhookData.entry[0].messaging?.[0]?.sender?.id || "unknown", to: facebookChannel.id, type: "text", content: webhookData.entry[0].messaging?.[0]?.message?.text || "", timestamp: new Date(), metadata: { platform: "facebook", }, }); return { success: true, data: result, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Error processing Facebook webhook", }; } } /** * Obtiene información de canales por plataforma */ async getChannelsByPlatform(req, res) { try { const { platform } = req.params; const organizationId = req.organization?.id; if (!organizationId) { res.status(400).json({ error: "Organization ID not found" }); return; } if (!platform) { res.status(400).json({ error: "Platform parameter is required" }); return; } const channelType = this.getChannelTypeFromPlatform(platform); if (!channelType) { res.status(400).json({ error: `Unsupported platform: ${platform}` }); return; } const channels = await this.channelRepository.findAll(organizationId); const platformChannels = channels.filter((channel) => channel.type === channelType); res.json({ success: true, data: { platform, channels: platformChannels, count: platformChannels.length, }, }); } catch (error) { console.error("❌ Error obteniendo canales por plataforma:", error); res.status(500).json({ error: "Internal server error" }); } } /** * Obtiene información de webhooks configurados */ async getWebhookInfo(req, res) { try { const organizationId = req.organization?.id; if (!organizationId) { res.status(400).json({ error: "Organization ID not found" }); return; } const channels = await this.channelRepository.findAll(organizationId); const webhookInfo = channels.map((channel) => ({ id: channel.id, type: channel.type, status: channel.status, webhookUrl: channel.config?.webhookUrl, isConfigured: channel.isConfigured(), })); res.json({ success: true, data: { organizationId, channels: webhookInfo, totalChannels: channels.length, activeChannels: channels.filter((c) => c.status === "active") .length, }, }); } catch (error) { console.error("❌ Error obteniendo información de webhooks:", error); res.status(500).json({ error: "Internal server error" }); } } /** * Mapea plataforma a tipo de canal */ getChannelTypeFromPlatform(platform) { const platformMap = { telegram: "telegram", whatsapp: "whatsapp", facebook: "facebook", instagram: "instagram", email: "email", sms: "sms", }; return platformMap[platform.toLowerCase()] || null; } } //# sourceMappingURL=unifiedWebhookController.js.map