diff --git a/src/apps/chatwoot/consumers/waha/message.any.ts b/src/apps/chatwoot/consumers/waha/message.any.ts index b2b81b235..a269c8738 100644 --- a/src/apps/chatwoot/consumers/waha/message.any.ts +++ b/src/apps/chatwoot/consumers/waha/message.any.ts @@ -86,7 +86,13 @@ export class MessageAnyHandler extends MessageBaseHandler { return msg; } - converter = new TextMessage(this.l, this.logger, this.waha, this.job); + converter = new TextMessage( + this.l, + this.logger, + this.waha, + this.job, + this.session, + ); msg = await converter.convert(payload, null); if (msg) { return msg; diff --git a/src/apps/chatwoot/i18n/locales/ar-AE.yaml b/src/apps/chatwoot/i18n/locales/ar-AE.yaml index 448ae9fa1..7867f7f57 100644 --- a/src/apps/chatwoot/i18n/locales/ar-AE.yaml +++ b/src/apps/chatwoot/i18n/locales/ar-AE.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **تم إرسال PIX نسخ ولصق** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **رد على حالة واتساب** + 🏷️ **النوع:** {{type}} + 📝 **نص الحالة الأصلي:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **رد على حالة واتساب** + 🏷️ **النوع:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **هذا النوع من الرسائل غير مدعوم في هذا الصندوق الوارد.** 📱 يرجى فتح **WhatsApp** لعرضه. diff --git a/src/apps/chatwoot/i18n/locales/bn-BD.yaml b/src/apps/chatwoot/i18n/locales/bn-BD.yaml index 57f88ba63..1c30e06b0 100644 --- a/src/apps/chatwoot/i18n/locales/bn-BD.yaml +++ b/src/apps/chatwoot/i18n/locales/bn-BD.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX কপি এবং পেস্ট পাঠানো হয়েছে** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **WhatsApp স্ট্যাটাসের জবাব** + 🏷️ **ধরন:** {{type}} + 📝 **মূল স্ট্যাটাসের টেক্সট:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **WhatsApp স্ট্যাটাসের জবাব** + 🏷️ **ধরন:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **এই ধরনের বার্তা এই ইনবক্সে সমর্থিত নয়।** 📱 এটি দেখতে অনুগ্রহ করে **WhatsApp** খুলুন। diff --git a/src/apps/chatwoot/i18n/locales/de-DE.yaml b/src/apps/chatwoot/i18n/locales/de-DE.yaml index 144585ed6..83c22f350 100644 --- a/src/apps/chatwoot/i18n/locales/de-DE.yaml +++ b/src/apps/chatwoot/i18n/locales/de-DE.yaml @@ -490,6 +490,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Kopieren und Einfügen gesendet** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Antwort auf WhatsApp-Status** + 🏷️ **Typ:** {{type}} + 📝 **Originaler Status-Text:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Antwort auf WhatsApp-Status** + 🏷️ **Typ:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **Dieser Nachrichtentyp wird in dieser Inbox nicht unterstützt.** 📱 Bitte öffne **WhatsApp**, um ihn anzusehen. diff --git a/src/apps/chatwoot/i18n/locales/en-US.yaml b/src/apps/chatwoot/i18n/locales/en-US.yaml index ac0efde81..211f2125e 100644 --- a/src/apps/chatwoot/i18n/locales/en-US.yaml +++ b/src/apps/chatwoot/i18n/locales/en-US.yaml @@ -268,6 +268,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Copy and Paste sent** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Reply to WhatsApp Status** + 🏷️ **Type:** {{type}} + 📝 **Original status text:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Reply to WhatsApp Status** + 🏷️ **Type:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.has.media.no.media: |- {{#content}} {{{content}}} diff --git a/src/apps/chatwoot/i18n/locales/es-ES.yaml b/src/apps/chatwoot/i18n/locales/es-ES.yaml index 3247cbf47..19f6b62ce 100644 --- a/src/apps/chatwoot/i18n/locales/es-ES.yaml +++ b/src/apps/chatwoot/i18n/locales/es-ES.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Copiar y Pegar enviado** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Respuesta al estado de WhatsApp** + 🏷️ **Tipo:** {{type}} + 📝 **Texto original del estado:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Respuesta al estado de WhatsApp** + 🏷️ **Tipo:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **Este tipo de mensaje no es compatible con esta bandeja de entrada.** 📱 Por favor, abre **WhatsApp** para verlo. diff --git a/src/apps/chatwoot/i18n/locales/fa-IR.yaml b/src/apps/chatwoot/i18n/locales/fa-IR.yaml index 6ea70279f..1abf58725 100644 --- a/src/apps/chatwoot/i18n/locales/fa-IR.yaml +++ b/src/apps/chatwoot/i18n/locales/fa-IR.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX کپی و چسباندن ارسال شد** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **پاسخ به وضعیت واتساپ** + 🏷️ **نوع:** {{type}} + 📝 **متن اصلی وضعیت:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **پاسخ به وضعیت واتساپ** + 🏷️ **نوع:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **این نوع پیام در این صندوق ورودی پشتیبانی نمی‌شود.** 📱 لطفاً برای مشاهده آن **WhatsApp** را باز کنید. diff --git a/src/apps/chatwoot/i18n/locales/fr-FR.yaml b/src/apps/chatwoot/i18n/locales/fr-FR.yaml index 42d235ce4..e656017dd 100644 --- a/src/apps/chatwoot/i18n/locales/fr-FR.yaml +++ b/src/apps/chatwoot/i18n/locales/fr-FR.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Copier et Coller envoyé** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Réponse au statut WhatsApp** + 🏷️ **Type :** {{type}} + 📝 **Texte original du statut :** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Réponse au statut WhatsApp** + 🏷️ **Type :** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **Ce type de message n’est pas pris en charge dans cette boîte de réception.** 📱 Veuillez ouvrir **WhatsApp** pour l’afficher. diff --git a/src/apps/chatwoot/i18n/locales/he-IL.yaml b/src/apps/chatwoot/i18n/locales/he-IL.yaml index f20c8aec6..cb51212f2 100644 --- a/src/apps/chatwoot/i18n/locales/he-IL.yaml +++ b/src/apps/chatwoot/i18n/locales/he-IL.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX העתק והדבק נשלח** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **תגובה לסטטוס ב-WhatsApp** + 🏷️ **סוג:** {{type}} + 📝 **טקסט הסטטוס המקורי:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **תגובה לסטטוס ב-WhatsApp** + 🏷️ **סוג:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **סוג הודעה זה אינו נתמך בתיבה זו.** 📱 אנא פתח/י את **WhatsApp** כדי לצפות בזה. diff --git a/src/apps/chatwoot/i18n/locales/hi-IN.yaml b/src/apps/chatwoot/i18n/locales/hi-IN.yaml index fc8fe5803..8074da5f9 100644 --- a/src/apps/chatwoot/i18n/locales/hi-IN.yaml +++ b/src/apps/chatwoot/i18n/locales/hi-IN.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX कॉपी और पेस्ट भेजा गया** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **WhatsApp स्टेटस का जवाब** + 🏷️ **प्रकार:** {{type}} + 📝 **मूल स्टेटस टेक्स्ट:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **WhatsApp स्टेटस का जवाब** + 🏷️ **प्रकार:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **इस प्रकार का संदेश इस इनबॉक्स में समर्थित नहीं है।** 📱 इसे देखने के लिए कृपया **WhatsApp** खोलें। diff --git a/src/apps/chatwoot/i18n/locales/id-ID.yaml b/src/apps/chatwoot/i18n/locales/id-ID.yaml index 05be670eb..43d0be4c6 100644 --- a/src/apps/chatwoot/i18n/locales/id-ID.yaml +++ b/src/apps/chatwoot/i18n/locales/id-ID.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Salin dan Tempel terkirim** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Balasan ke Status WhatsApp** + 🏷️ **Tipe:** {{type}} + 📝 **Teks status asli:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Balasan ke Status WhatsApp** + 🏷️ **Tipe:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **Jenis pesan ini tidak didukung di kotak masuk ini.** 📱 Silakan buka **WhatsApp** untuk melihatnya. diff --git a/src/apps/chatwoot/i18n/locales/it-IT.yaml b/src/apps/chatwoot/i18n/locales/it-IT.yaml index 40fe3f0d4..332c5796e 100644 --- a/src/apps/chatwoot/i18n/locales/it-IT.yaml +++ b/src/apps/chatwoot/i18n/locales/it-IT.yaml @@ -268,6 +268,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Copia e Incolla inviato** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Risposta allo stato di WhatsApp** + 🏷️ **Tipo:** {{type}} + 📝 **Testo originale dello stato:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Risposta allo stato di WhatsApp** + 🏷️ **Tipo:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.has.media.no.media: |- {{#content}} {{{content}}} diff --git a/src/apps/chatwoot/i18n/locales/pa-PK.yaml b/src/apps/chatwoot/i18n/locales/pa-PK.yaml index e392454a3..1d17e51b0 100644 --- a/src/apps/chatwoot/i18n/locales/pa-PK.yaml +++ b/src/apps/chatwoot/i18n/locales/pa-PK.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX ਕਾਪੀ ਅਤੇ ਪੇਸਟ ਭੇਜਿਆ ਗਿਆ** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **WhatsApp ਸਟੇਟਸ ਦਾ ਜਵਾਬ** + 🏷️ **ਕਿਸਮ:** {{type}} + 📝 **ਅਸਲ ਸਟੇਟਸ ਲਿਖਤ:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **WhatsApp ਸਟੇਟਸ ਦਾ ਜਵਾਬ** + 🏷️ **ਕਿਸਮ:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **ਇਹ ਸੁਨੇਹੇ ਦੀ ਕਿਸਮ ਇਸ ਇਨਬਾਕਸ ਵਿੱਚ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ।** 📱 ਇਸਨੂੰ ਦੇਖਣ ਲਈ ਕਿਰਪਾ ਕਰਕੇ **WhatsApp** ਖੋਲ੍ਹੋ। diff --git a/src/apps/chatwoot/i18n/locales/pt-BR.yaml b/src/apps/chatwoot/i18n/locales/pt-BR.yaml index e4a4f0e1e..b21294d37 100644 --- a/src/apps/chatwoot/i18n/locales/pt-BR.yaml +++ b/src/apps/chatwoot/i18n/locales/pt-BR.yaml @@ -492,6 +492,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Copia e Cola enviado** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Resposta a Status do WhatsApp** + 🏷️ **Tipo:** {{type}} + 📝 **Texto original do status:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Resposta a Status do WhatsApp** + 🏷️ **Tipo:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **Esse tipo de mensagem não é suportado nesta caixa de entrada.** 📱 Por favor, abra o **WhatsApp** para visualizá-la. diff --git a/src/apps/chatwoot/i18n/locales/ru-RU.yaml b/src/apps/chatwoot/i18n/locales/ru-RU.yaml index 602c19f82..f667ebd1a 100644 --- a/src/apps/chatwoot/i18n/locales/ru-RU.yaml +++ b/src/apps/chatwoot/i18n/locales/ru-RU.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Копировать и вставить отправлен** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Ответ на статус WhatsApp** + 🏷️ **Тип:** {{type}} + 📝 **Оригинальный текст статуса:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Ответ на статус WhatsApp** + 🏷️ **Тип:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **Этот тип сообщения не поддерживается в этом Inbox.** 📱 Пожалуйста, откройте **WhatsApp**, чтобы просмотреть. diff --git a/src/apps/chatwoot/i18n/locales/tr-TR.yaml b/src/apps/chatwoot/i18n/locales/tr-TR.yaml index 265b9d8d6..cd3b551f6 100644 --- a/src/apps/chatwoot/i18n/locales/tr-TR.yaml +++ b/src/apps/chatwoot/i18n/locales/tr-TR.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Kopyala ve Yapıştır gönderildi** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **WhatsApp Durumuna Yanıt** + 🏷️ **Tür:** {{type}} + 📝 **Orijinal durum metni:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **WhatsApp Durumuna Yanıt** + 🏷️ **Tür:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **Bu mesaj türü bu gelen kutusunda desteklenmiyor.** 📱 Görüntülemek için lütfen **WhatsApp’ı** açın. diff --git a/src/apps/chatwoot/i18n/locales/uk-UA.yaml b/src/apps/chatwoot/i18n/locales/uk-UA.yaml index 626801238..ea43ef502 100644 --- a/src/apps/chatwoot/i18n/locales/uk-UA.yaml +++ b/src/apps/chatwoot/i18n/locales/uk-UA.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX Копіювати та Вставити надіслано** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **Відповідь на статус WhatsApp** + 🏷️ **Тип:** {{type}} + 📝 **Оригінальний текст статусу:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **Відповідь на статус WhatsApp** + 🏷️ **Тип:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **Цей тип повідомлення не підтримується в цих вхідних.** 📱 Будь ласка, відкрийте **WhatsApp**, щоб переглянути. diff --git a/src/apps/chatwoot/i18n/locales/ur-PK.yaml b/src/apps/chatwoot/i18n/locales/ur-PK.yaml index a8b4a5674..7b9747160 100644 --- a/src/apps/chatwoot/i18n/locales/ur-PK.yaml +++ b/src/apps/chatwoot/i18n/locales/ur-PK.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX کاپی اور پیسٹ بھیج دیا گیا** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **WhatsApp اسٹیٹس کا جواب** + 🏷️ **قسم:** {{type}} + 📝 **اصل اسٹیٹس کا متن:** {{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **WhatsApp اسٹیٹس کا جواب** + 🏷️ **قسم:** {{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **اس قسم کا پیغام اس انبکس میں معاونت یافتہ نہیں ہے۔** 📱 اسے دیکھنے کے لیے براہ کرم **WhatsApp** کھولیں۔ diff --git a/src/apps/chatwoot/i18n/locales/zh-CN.yaml b/src/apps/chatwoot/i18n/locales/zh-CN.yaml index 0ad7eed08..d5fd0e735 100644 --- a/src/apps/chatwoot/i18n/locales/zh-CN.yaml +++ b/src/apps/chatwoot/i18n/locales/zh-CN.yaml @@ -487,6 +487,19 @@ whatsapp.to.chatwoot.message.pix: |- 💳 **PIX 复制粘贴已发送** {{/pixData}} +whatsapp.to.chatwoot.message.status.reply.with.text: |- + 📣 **回复 WhatsApp 状态** + 🏷️ **类型:**{{type}} + 📝 **原始状态文本:**{{quotedText}} + + {{content}} + +whatsapp.to.chatwoot.message.status.reply.without.text: |- + 📣 **回复 WhatsApp 状态** + 🏷️ **类型:**{{type}} + + {{content}} + whatsapp.to.chatwoot.message.unsupported: |- ⚠️ **此收件箱不支持此消息类型。** 📱 请打开 **WhatsApp** 查看。 diff --git a/src/apps/chatwoot/i18n/templates.ts b/src/apps/chatwoot/i18n/templates.ts index d37239b53..6dd3e1e6b 100644 --- a/src/apps/chatwoot/i18n/templates.ts +++ b/src/apps/chatwoot/i18n/templates.ts @@ -54,6 +54,8 @@ export enum TKey { WA_TO_CW_MESSAGE_POLL = 'whatsapp.to.chatwoot.message.poll', WA_TO_CW_MESSAGE_EVENT = 'whatsapp.to.chatwoot.message.event', WA_TO_CW_MESSAGE_PIX = 'whatsapp.to.chatwoot.message.pix', + WA_TO_CW_MESSAGE_STATUS_REPLY_WITH_TEXT = 'whatsapp.to.chatwoot.message.status.reply.with.text', + WA_TO_CW_MESSAGE_STATUS_REPLY_WITHOUT_TEXT = 'whatsapp.to.chatwoot.message.status.reply.without.text', WA_TO_CW_MESSAGE_UNSUPPORTED = 'whatsapp.to.chatwoot.message.unsupported', WA_TO_CW_MESSAGE_FACEBOOK_AD = 'whatsapp.to.chatwoot.message.facebook.ad', WA_TO_CW_MESSAGE_LIST = 'whatsapp.to.chatwoot.message.list', @@ -189,6 +191,15 @@ export type TemplatePayloads = { message: proto.Message | null; pixData: PixTemplatePayload; }; + [TKey.WA_TO_CW_MESSAGE_STATUS_REPLY_WITH_TEXT]: { + type: string; + quotedText: string; + content: string; + }; + [TKey.WA_TO_CW_MESSAGE_STATUS_REPLY_WITHOUT_TEXT]: { + type: string; + content: string; + }; [TKey.WA_TO_CW_MESSAGE_UNSUPPORTED]: { details: Link }; [TKey.WA_TO_CW_MESSAGE_FACEBOOK_AD]: { payload: WAMessage; diff --git a/src/apps/chatwoot/messages/to/chatwoot/TextMessage.ts b/src/apps/chatwoot/messages/to/chatwoot/TextMessage.ts index bf9b55f3c..5a785279b 100644 --- a/src/apps/chatwoot/messages/to/chatwoot/TextMessage.ts +++ b/src/apps/chatwoot/messages/to/chatwoot/TextMessage.ts @@ -11,16 +11,33 @@ import { MessageToChatWootConverter } from '@waha/apps/chatwoot/messages/to/chat import { WhatsappToMarkdown } from '@waha/apps/chatwoot/messages/to/chatwoot/utils/markdown'; import { JobLink } from '@waha/apps/app_sdk/JobUtils'; import { Job } from 'bullmq'; +import { WAHASessionAPI } from '@waha/apps/app_sdk/waha/WAHASelf'; // eslint-disable-next-line @typescript-eslint/no-var-requires const mime = require('mime-types'); +type StatusReplyType = 'text' | 'image' | 'audio' | 'video' | 'unknown'; + +interface StatusReplyMediaDetails { + url: string; + mimetype?: string; + type: 'image' | 'audio' | 'video'; +} + +interface StatusReplyDetails { + statusType: StatusReplyType; + quotedText?: string; + media?: StatusReplyMediaDetails; + replyMessageId?: string; +} + export class TextMessage implements MessageToChatWootConverter { constructor( private readonly locale: Locale, private readonly logger: ILogger, private readonly waha: WAHASelf, private readonly job: Job, + private readonly session: WAHASessionAPI, ) {} async convert( @@ -28,8 +45,12 @@ export class TextMessage implements MessageToChatWootConverter { protoMessage: proto.Message | null, ): Promise { void protoMessage; - const attachments = await this.getAttachments(payload); + const statusReplyDetails = this.getStatusReplyDetails(payload); + const attachments = await this.getAttachments(payload, statusReplyDetails); let content = this.locale.key(TKey.WA_TO_CW_MESSAGE).render({ payload }); + if (statusReplyDetails) { + content = this.wrapStatusReplyContent(content, statusReplyDetails); + } if (isEmptyString(content) && attachments.length === 0) { // No media, no content - return null so we can process it later return null; @@ -52,33 +73,222 @@ export class TextMessage implements MessageToChatWootConverter { } return { content: WhatsappToMarkdown(content), - attachments, + attachments: attachments, private: undefined, }; } - private async getAttachments(payload: WAMessage): Promise { - const hasMedia = payload.media?.url; - if (!hasMedia) { - return []; + private async getAttachments( + payload: WAMessage, + statusReplyDetails: StatusReplyDetails | null, + ): Promise { + const attachments: SendAttachment[] = []; + const media = payload.media; + if (media?.url) { + const attachment = await this.downloadAttachment(media.url, media.filename, { + fallbackBaseName: 'no-filename', + mimetype: media.mimetype, + }); + if (attachment) { + attachments.push(attachment); + } + } + + const statusMedia = + (await this.getStatusReplyMedia(payload, statusReplyDetails)) || + statusReplyDetails?.media; + if (!statusMedia || !statusMedia.url) { + return attachments; } - const media = payload.media!; - this.logger.debug(`Downloading media from '${media.url}'...`); - const buffer = await this.waha.fetch(media.url); - const fileContent = buffer.toString('base64'); - let filename = media.filename; - if (!filename) { - const extension = mime.extension(media.mimetype); - filename = `no-filename.${extension}`; + const statusAttachment = await this.downloadAttachment( + statusMedia.url, + undefined, + { + fallbackBaseName: `status-reply-${statusMedia.type}`, + mimetype: statusMedia.mimetype, + }, + ); + if (statusAttachment) { + attachments.push(statusAttachment); + } + return attachments; + } + + private async getStatusReplyMedia( + payload: WAMessage, + statusReplyDetails: StatusReplyDetails | null, + ): Promise { + void payload; + if (!statusReplyDetails?.replyMessageId) { + return statusReplyDetails?.media || null; } + try { + const quotedMessage = await this.session.getMessageById( + 'status@broadcast', + statusReplyDetails.replyMessageId, + true, + ); + const quotedMedia = quotedMessage?.media; + if (!quotedMedia?.url) { + return statusReplyDetails?.media || null; + } + return { + type: statusReplyDetails.statusType as 'image' | 'audio' | 'video', + url: quotedMedia.url, + mimetype: quotedMedia.mimetype || statusReplyDetails?.media?.mimetype, + }; + } catch (error) { + this.logger.warn( + `Failed to resolve status reply media via message id '${statusReplyDetails.replyMessageId}'`, + ); + this.logger.debug(error); + return statusReplyDetails?.media || null; + } + } + + private async downloadAttachment( + url: string, + filename: string | undefined, + options: { + fallbackBaseName: string; + mimetype?: string; + }, + ): Promise { + this.logger.debug(`Downloading media from '${url}'...`); + const buffer = await this.waha.fetch(url); + const fileContent = buffer.toString('base64'); + const resolvedFilename = this.resolveFilename( + filename, + options.fallbackBaseName, + options.mimetype, + ); const attachment: SendAttachment = { content: fileContent, - filename, + filename: resolvedFilename, encoding: 'base64', }; - this.logger.info(`Downloaded media from '${media.url}' as '${filename}'`); - return [attachment]; + this.logger.info(`Downloaded media from '${url}' as '${resolvedFilename}'`); + return attachment; + } + + private resolveFilename( + filename: string | undefined, + fallbackBaseName: string, + mimetype: string | undefined, + ): string { + if (!isEmptyString(filename)) { + return filename!; + } + const extensionFromMime = mimetype ? mime.extension(mimetype) : false; + const extension = extensionFromMime || 'bin'; + return `${fallbackBaseName}.${extension}`; + } + + private wrapStatusReplyContent( + content: string | null, + statusReplyDetails: StatusReplyDetails, + ): string { + const contentWithFallback = content ?? ''; + if (statusReplyDetails.quotedText) { + return this.locale.r(TKey.WA_TO_CW_MESSAGE_STATUS_REPLY_WITH_TEXT, { + type: statusReplyDetails.statusType, + quotedText: statusReplyDetails.quotedText, + content: contentWithFallback, + }); + } + + return this.locale.r(TKey.WA_TO_CW_MESSAGE_STATUS_REPLY_WITHOUT_TEXT, { + type: statusReplyDetails.statusType, + content: contentWithFallback, + }); + } + + private getStatusReplyDetails(payload: WAMessage): StatusReplyDetails | null { + if (!payload.replyTo) { + return null; + } + + const contextInfo = (payload as any)?._data?.Message?.extendedTextMessage + ?.contextInfo; + const remoteJid = contextInfo?.remoteJID ?? contextInfo?.remoteJid; + if (remoteJid !== 'status@broadcast') { + return null; + } + + const replyData = (payload.replyTo as any)?._data; + const replyMessageId = payload.replyTo.id; + if (!replyData) { + return { + statusType: 'unknown', + replyMessageId: replyMessageId, + }; + } + + const imageMessage = replyData.imageMessage; + if (imageMessage) { + return { + statusType: 'image', + media: this.getStatusReplyMediaDetails('image', imageMessage), + replyMessageId: replyMessageId, + }; + } + + const audioMessage = replyData.audioMessage; + if (audioMessage) { + return { + statusType: 'audio', + media: this.getStatusReplyMediaDetails('audio', audioMessage), + replyMessageId: replyMessageId, + }; + } + + const videoMessage = replyData.videoMessage; + if (videoMessage) { + return { + statusType: 'video', + media: this.getStatusReplyMediaDetails('video', videoMessage), + replyMessageId: replyMessageId, + }; + } + + const extendedTextMessage = replyData.extendedTextMessage; + if (extendedTextMessage) { + return { + statusType: 'text', + quotedText: extendedTextMessage.text, + replyMessageId: replyMessageId, + }; + } + + const conversation = replyData.conversation; + if (conversation) { + return { + statusType: 'text', + quotedText: conversation, + replyMessageId: replyMessageId, + }; + } + + return { + statusType: 'unknown', + replyMessageId: replyMessageId, + }; + } + + private getStatusReplyMediaDetails( + type: 'image' | 'audio' | 'video', + data: any, + ): StatusReplyMediaDetails | undefined { + const url = data?.URL ?? data?.url; + if (!url) { + return undefined; + } + return { + type: type, + url: url, + mimetype: data?.mimetype, + }; } }