feat(webhook): message incoming/outgoing (#181)

* feat(webhook): message created incoming/outgoing

* feat(webhook): rename message_created_incoming/outgoing to message_incoming/outgoing

* chore: remove redundant comment
This commit is contained in:
Gabriel Jablonski 2026-01-03 00:11:50 -03:00 committed by GitHub
parent 8655e5b025
commit 85e8258a87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 112 additions and 3 deletions

View File

@ -38,6 +38,8 @@
"CONVERSATION_STATUS_CHANGED": "Conversation Status Changed",
"CONVERSATION_UPDATED": "Conversation Updated",
"MESSAGE_CREATED": "Message created",
"MESSAGE_INCOMING": "Incoming message",
"MESSAGE_OUTGOING": "Outgoing message",
"MESSAGE_UPDATED": "Message updated",
"WEBWIDGET_TRIGGERED": "Live chat widget opened by the user",
"CONTACT_CREATED": "Contact created",

View File

@ -38,6 +38,8 @@
"CONVERSATION_STATUS_CHANGED": "Status de conversa alterado",
"CONVERSATION_UPDATED": "Conversa Atualizada",
"MESSAGE_CREATED": "Mensagem criada",
"MESSAGE_INCOMING": "Mensagem recebida",
"MESSAGE_OUTGOING": "Mensagem enviada",
"MESSAGE_UPDATED": "Mensagem atualizada",
"WEBWIDGET_TRIGGERED": "Widget de chat aberto pelo usuário",
"CONTACT_CREATED": "Contato criado",

View File

@ -14,6 +14,8 @@ const SUPPORTED_WEBHOOK_EVENTS = [
'conversation_status_changed',
'conversation_updated',
'message_created',
'message_incoming',
'message_outgoing',
'message_updated',
'webwidget_triggered',
'contact_created',

View File

@ -30,6 +30,29 @@ class WebhookListener < BaseListener
payload = message.webhook_data.merge(event: __method__.to_s)
deliver_webhook_payloads(payload, inbox)
message_incoming(event)
message_outgoing(event)
end
def message_incoming(event)
message = extract_message_and_account(event)[0]
return unless message.webhook_sendable?
return unless message.incoming?
payload = message.webhook_data.merge(event: __method__.to_s)
deliver_account_webhooks(payload, message.account)
end
def message_outgoing(event)
message = extract_message_and_account(event)[0]
return unless message.webhook_sendable?
return unless message.outgoing?
payload = message.webhook_data.merge(event: __method__.to_s)
deliver_account_webhooks(payload, message.account)
end
def message_updated(event)

View File

@ -27,8 +27,8 @@ class Webhook < ApplicationRecord
enum webhook_type: { account_type: 0, inbox_type: 1 }
ALLOWED_WEBHOOK_EVENTS = %w[conversation_status_changed conversation_updated conversation_created contact_created contact_updated
message_created message_updated webwidget_triggered inbox_created inbox_updated
conversation_typing_on conversation_typing_off provider_event_received].freeze
message_created message_incoming message_outgoing message_updated webwidget_triggered
inbox_created inbox_updated conversation_typing_on conversation_typing_off provider_event_received].freeze
private

View File

@ -1,5 +1,5 @@
class Webhooks::ErrorHandler
SUPPORTED_EVENTS = %w[message_created message_updated].freeze
SUPPORTED_EVENTS = %w[message_created message_incoming message_outgoing message_updated].freeze
def initialize(payload, webhook_type, error)
@payload = payload

View File

@ -101,6 +101,86 @@ describe WebhookListener do
end
end
describe '#message_incoming' do
let(:event_name) { :'message.created' }
let!(:incoming_message) do
create(:message, message_type: 'incoming',
account: account, inbox: inbox, conversation: conversation)
end
let!(:incoming_message_event) { Events::Base.new(event_name, Time.zone.now, message: incoming_message) }
context 'when webhook is not configured' do
it 'does not trigger webhook' do
expect(WebhookJob).to receive(:perform_later).exactly(0).times
listener.message_incoming(incoming_message_event)
end
end
context 'when webhook is configured and message is incoming' do
it 'triggers the webhook event' do
webhook = create(:webhook, inbox: inbox, account: account, subscriptions: ['message_incoming'])
expect(WebhookJob).to receive(:perform_later).with(webhook.url, incoming_message.webhook_data.merge(event: 'message_incoming')).once
listener.message_incoming(incoming_message_event)
end
end
context 'when webhook is configured and message is outgoing' do
it 'does not trigger the webhook event' do
create(:webhook, inbox: inbox, account: account, subscriptions: ['message_incoming'])
expect(WebhookJob).not_to receive(:perform_later)
listener.message_incoming(message_created_event)
end
end
context 'when webhook is configured but event is not subscribed' do
it 'does not trigger the webhook event' do
create(:webhook, subscriptions: ['conversation_created'], inbox: inbox, account: account)
expect(WebhookJob).not_to receive(:perform_later)
listener.message_incoming(incoming_message_event)
end
end
end
describe '#message_outgoing' do
let(:event_name) { :'message.created' }
let!(:incoming_message) do
create(:message, message_type: 'incoming',
account: account, inbox: inbox, conversation: conversation)
end
let!(:incoming_message_event) { Events::Base.new(event_name, Time.zone.now, message: incoming_message) }
context 'when webhook is not configured' do
it 'does not trigger webhook' do
expect(WebhookJob).to receive(:perform_later).exactly(0).times
listener.message_outgoing(message_created_event)
end
end
context 'when webhook is configured and message is outgoing' do
it 'triggers the webhook event' do
webhook = create(:webhook, inbox: inbox, account: account, subscriptions: ['message_outgoing'])
expect(WebhookJob).to receive(:perform_later).with(webhook.url, message.webhook_data.merge(event: 'message_outgoing')).once
listener.message_outgoing(message_created_event)
end
end
context 'when webhook is configured and message is incoming' do
it 'does not trigger the webhook event' do
create(:webhook, inbox: inbox, account: account, subscriptions: ['message_outgoing'])
expect(WebhookJob).not_to receive(:perform_later)
listener.message_outgoing(incoming_message_event)
end
end
context 'when webhook is configured but event is not subscribed' do
it 'does not trigger the webhook event' do
create(:webhook, subscriptions: ['conversation_created'], inbox: inbox, account: account)
expect(WebhookJob).not_to receive(:perform_later)
listener.message_outgoing(message_created_event)
end
end
end
describe '#conversation_created' do
let(:event_name) { :'conversation.created' }