Files
leadchat/app/services/whatsapp/incoming_message_service_helpers.rb
Pranav Raj S b7c9f779ad fix: Avoid processing reactions, ephemeral, request_welcome or unsupported messages (#8780)
Currently, we do not support reactions, ephemeral messages, or the request_welcome event for the WhatsApp channel. However, if this is the first event we receive in Chatwoot (i.e., there is no previous conversation or contact in Chatwoot), it will create a contact and a conversation without any messages. This confuses our customer, as it may appear that Chatwoot has missed some messages. There are multiple cases where this might be the first event we receive in Chatwoot. One quick example is when the user has sent an outbound campaign from another tool and their customers reacted to the message.

Another event like this is request_welcome event. WhatsApp has a concept for welcome messages. You can send an outbound message even though the user has not send a message. You can receive notifications through a webhook whenever a WhatsApp user initiates a chat with you for the first time. (Read the Welcome message section: https://developers.facebook.com/docs/whatsapp/cloud-api/phone-numbers/conversational-components/ ). Although this can help the business send a pro-active message to the user, we don't have it scoped in our feature set. For now, I'm ignoring this event.

Fixes https://linear.app/chatwoot/issue/CW-3018/whatsapp-handle-request-welcome-case-properly
Fixes https://linear.app/chatwoot/issue/CW-3017/whatsapp-handle-reactions-properly
2024-01-25 11:40:18 +04:00

117 lines
3.7 KiB
Ruby

module Whatsapp::IncomingMessageServiceHelpers
def download_attachment_file(attachment_payload)
Down.download(inbox.channel.media_url(attachment_payload[:id]), headers: inbox.channel.api_headers)
end
def conversation_params
{
account_id: @inbox.account_id,
inbox_id: @inbox.id,
contact_id: @contact.id,
contact_inbox_id: @contact_inbox.id
}
end
def processed_params
@processed_params ||= params
end
def account
@account ||= inbox.account
end
def message_type
@processed_params[:messages].first[:type]
end
def message_content(message)
# TODO: map interactive messages back to button messages in chatwoot
message.dig(:text, :body) ||
message.dig(:button, :text) ||
message.dig(:interactive, :button_reply, :title) ||
message.dig(:interactive, :list_reply, :title) ||
message.dig(:name, :formatted_name)
end
def file_content_type(file_type)
return :image if %w[image sticker].include?(file_type)
return :audio if %w[audio voice].include?(file_type)
return :video if ['video'].include?(file_type)
return :location if ['location'].include?(file_type)
return :contact if ['contacts'].include?(file_type)
:file
end
def unprocessable_message_type?(message_type)
%w[reaction ephemeral unsupported request_welcome].include?(message_type)
end
def brazil_phone_number?(phone_number)
phone_number.match(/^55/)
end
# ref: https://github.com/chatwoot/chatwoot/issues/5840
def normalised_brazil_mobile_number(phone_number)
# DDD : Area codes in Brazil are popularly known as "DDD codes" (códigos DDD) or simply "DDD", from the initials of "direct distance dialing"
# https://en.wikipedia.org/wiki/Telephone_numbers_in_Brazil
ddd = phone_number[2, 2]
# Remove country code and DDD to obtain the number
number = phone_number[4, phone_number.length - 4]
normalised_number = "55#{ddd}#{number}"
# insert 9 to convert the number to the new mobile number format
normalised_number = "55#{ddd}9#{number}" if normalised_number.length != 13
normalised_number
end
def processed_waid(waid)
# in case of Brazil, we need to do additional processing
# https://github.com/chatwoot/chatwoot/issues/5840
if brazil_phone_number?(waid)
# check if there is an existing contact inbox with the normalised waid
# We will create conversation against it
contact_inbox = inbox.contact_inboxes.find_by(source_id: normalised_brazil_mobile_number(waid))
# if there is no contact inbox with the waid without 9,
# We will create contact inboxes and contacts with the number 9 added
waid = contact_inbox.source_id if contact_inbox.present?
end
waid
end
def error_webhook_event?(message)
message.key?('errors')
end
def log_error(message)
Rails.logger.warn "Whatsapp Error: #{message['errors'][0]['title']} - contact: #{message['from']}"
end
def process_in_reply_to(message)
@in_reply_to_external_id = message['context']&.[]('id')
end
def find_message_by_source_id(source_id)
return unless source_id
@message = Message.find_by(source_id: source_id)
end
def message_under_process?
key = format(Redis::RedisKeys::MESSAGE_SOURCE_KEY, id: @processed_params[:messages].first[:id])
Redis::Alfred.get(key)
end
def cache_message_source_id_in_redis
return if @processed_params.try(:[], :messages).blank?
key = format(Redis::RedisKeys::MESSAGE_SOURCE_KEY, id: @processed_params[:messages].first[:id])
::Redis::Alfred.setex(key, true)
end
def clear_message_source_id_from_redis
key = format(Redis::RedisKeys::MESSAGE_SOURCE_KEY, id: @processed_params[:messages].first[:id])
::Redis::Alfred.delete(key)
end
end