skailan-conversations
Version:
Servicio de conversaciones y mensajería para Skailan
348 lines • 13.7 kB
JavaScript
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