mirror of
https://github.com/lingble/chatwoot.git
synced 2025-10-29 10:12:34 +00:00
feat: Add webhook events for contact created, updated (#6415)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
@@ -163,7 +163,7 @@ RSpec/NamedSubject:
|
||||
Enabled: false
|
||||
# we should bring this down
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Max: 12
|
||||
Max: 14
|
||||
|
||||
AllCops:
|
||||
NewCops: enable
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"CONVERSATION_UPDATED": "Conversation Updated",
|
||||
"MESSAGE_CREATED": "Message created",
|
||||
"MESSAGE_UPDATED": "Message updated",
|
||||
"WEBWIDGET_TRIGGERED": "Live chat widget opened by the user"
|
||||
"WEBWIDGET_TRIGGERED": "Live chat widget opened by the user",
|
||||
"CONTACT_CREATED": "Contact created",
|
||||
"CONTACT_UPDATED": "Contact update"
|
||||
}
|
||||
},
|
||||
"END_POINT": {
|
||||
|
||||
@@ -61,6 +61,8 @@ const SUPPORTED_WEBHOOK_EVENTS = [
|
||||
'message_created',
|
||||
'message_updated',
|
||||
'webwidget_triggered',
|
||||
'contact_created',
|
||||
'contact_updated',
|
||||
];
|
||||
|
||||
export default {
|
||||
|
||||
@@ -51,10 +51,25 @@ class WebhookListener < BaseListener
|
||||
deliver_webhook_payloads(payload, inbox)
|
||||
end
|
||||
|
||||
def contact_created(event)
|
||||
contact, account = extract_contact_and_account(event)
|
||||
payload = contact.webhook_data.merge(event: __method__.to_s)
|
||||
deliver_account_webhooks(payload, account)
|
||||
end
|
||||
|
||||
def contact_updated(event)
|
||||
contact, account = extract_contact_and_account(event)
|
||||
changed_attributes = extract_changed_attributes(event)
|
||||
return if changed_attributes.blank?
|
||||
|
||||
payload = contact.webhook_data.merge(event: __method__.to_s, changed_attributes: changed_attributes)
|
||||
deliver_account_webhooks(payload, account)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def deliver_account_webhooks(payload, inbox)
|
||||
inbox.account.webhooks.account_type.each do |webhook|
|
||||
def deliver_account_webhooks(payload, account)
|
||||
account.webhooks.account_type.each do |webhook|
|
||||
next unless webhook.subscriptions.include?(payload[:event])
|
||||
|
||||
WebhookJob.perform_later(webhook.url, payload)
|
||||
@@ -69,7 +84,7 @@ class WebhookListener < BaseListener
|
||||
end
|
||||
|
||||
def deliver_webhook_payloads(payload, inbox)
|
||||
deliver_account_webhooks(payload, inbox)
|
||||
deliver_account_webhooks(payload, inbox.account)
|
||||
deliver_api_inbox_webhooks(payload, inbox)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -121,11 +121,16 @@ class Contact < ApplicationRecord
|
||||
|
||||
def webhook_data
|
||||
{
|
||||
id: id,
|
||||
name: name,
|
||||
account: account.webhook_data,
|
||||
additional_attributes: additional_attributes,
|
||||
avatar: avatar_url,
|
||||
type: 'contact',
|
||||
account: account.webhook_data
|
||||
custom_attributes: custom_attributes,
|
||||
email: email,
|
||||
id: id,
|
||||
identifier: identifier,
|
||||
name: name,
|
||||
phone_number: phone_number,
|
||||
thumbnail: avatar_url
|
||||
}
|
||||
end
|
||||
|
||||
@@ -180,7 +185,7 @@ class Contact < ApplicationRecord
|
||||
end
|
||||
|
||||
def dispatch_update_event
|
||||
Rails.configuration.dispatcher.dispatch(CONTACT_UPDATED, Time.zone.now, contact: self)
|
||||
Rails.configuration.dispatcher.dispatch(CONTACT_UPDATED, Time.zone.now, contact: self, changed_attributes: previous_changes)
|
||||
end
|
||||
|
||||
def dispatch_destroy_event
|
||||
|
||||
@@ -25,8 +25,8 @@ class Webhook < ApplicationRecord
|
||||
validate :validate_webhook_subscriptions
|
||||
enum webhook_type: { account_type: 0, inbox_type: 1 }
|
||||
|
||||
ALLOWED_WEBHOOK_EVENTS = %w[conversation_status_changed conversation_updated conversation_created message_created message_updated
|
||||
webwidget_triggered].freeze
|
||||
ALLOWED_WEBHOOK_EVENTS = %w[conversation_status_changed conversation_updated conversation_created contact_created contact_updated
|
||||
message_created message_updated webwidget_triggered].freeze
|
||||
|
||||
private
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
class UpdateDefaultOnSubscriptionsWebhooks < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
change_column_default :webhooks, :subscriptions,
|
||||
from: %w[conversation_status_changed conversation_updated conversation_created
|
||||
message_created message_updated webwidget_triggered],
|
||||
to: %w[conversation_status_changed conversation_updated conversation_created
|
||||
contact_created contact_updated message_created message_updated webwidget_triggered]
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2022_12_30_113108) do
|
||||
ActiveRecord::Schema.define(version: 2023_02_09_033203) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
@@ -851,7 +851,7 @@ ActiveRecord::Schema.define(version: 2022_12_30_113108) do
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.integer "webhook_type", default: 0
|
||||
t.jsonb "subscriptions", default: ["conversation_status_changed", "conversation_updated", "conversation_created", "message_created", "message_updated", "webwidget_triggered"]
|
||||
t.jsonb "subscriptions", default: ["conversation_status_changed", "conversation_updated", "conversation_created", "contact_created", "contact_updated", "message_created", "message_updated", "webwidget_triggered"]
|
||||
t.index ["account_id", "url"], name: "index_webhooks_on_account_id_and_url", unique: true
|
||||
end
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ RSpec.describe 'Webhooks API', type: :request do
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(
|
||||
JSON.parse(response.body)['payload']['webhook']['subscriptions']
|
||||
).to eql %w[conversation_status_changed conversation_updated conversation_created message_created message_updated
|
||||
webwidget_triggered]
|
||||
).to eql %w[conversation_status_changed conversation_updated conversation_created contact_created contact_updated
|
||||
message_created message_updated webwidget_triggered]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,6 +8,8 @@ FactoryBot.define do
|
||||
conversation_status_changed
|
||||
conversation_updated
|
||||
conversation_created
|
||||
contact_created
|
||||
contact_updated
|
||||
message_created
|
||||
message_updated
|
||||
webwidget_triggered
|
||||
|
||||
@@ -5,6 +5,7 @@ describe WebhookListener do
|
||||
let(:report_identity) { Reports::UpdateAccountIdentity.new(account, Time.zone.now) }
|
||||
let!(:user) { create(:user, account: account) }
|
||||
let!(:inbox) { create(:inbox, account: account) }
|
||||
let!(:contact) { create(:contact, account: account) }
|
||||
let!(:conversation) { create(:conversation, account: account, inbox: inbox, assignee: user) }
|
||||
let!(:message) do
|
||||
create(:message, message_type: 'outgoing',
|
||||
@@ -12,6 +13,7 @@ describe WebhookListener do
|
||||
end
|
||||
let!(:message_created_event) { Events::Base.new(event_name, Time.zone.now, message: message) }
|
||||
let!(:conversation_created_event) { Events::Base.new(event_name, Time.zone.now, conversation: conversation) }
|
||||
let!(:contact_event) { Events::Base.new(event_name, Time.zone.now, contact: contact) }
|
||||
|
||||
describe '#message_created' do
|
||||
let(:event_name) { :'message.created' }
|
||||
@@ -159,4 +161,60 @@ describe WebhookListener do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#contact_created' do
|
||||
let(:event_name) { :'contact.created' }
|
||||
|
||||
context 'when webhook is not configured' do
|
||||
it 'does not trigger webhook' do
|
||||
expect(WebhookJob).to receive(:perform_later).exactly(0).times
|
||||
listener.contact_created(contact_event)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when webhook is configured' do
|
||||
it 'triggers webhook' do
|
||||
webhook = create(:webhook, account: account)
|
||||
expect(WebhookJob).to receive(:perform_later).with(webhook.url, contact.webhook_data.merge(event: 'contact_created')).once
|
||||
listener.contact_created(contact_event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#contact_updated' do
|
||||
let(:event_name) { :'contact.updated' }
|
||||
let!(:contact_updated_event) { Events::Base.new(event_name, Time.zone.now, contact: contact, changed_attributes: changed_attributes) }
|
||||
let(:changed_attributes) { { 'name' => ['Jane', 'Jane Doe'] } }
|
||||
|
||||
context 'when webhook is not configured' do
|
||||
it 'does not trigger webhook' do
|
||||
expect(WebhookJob).to receive(:perform_later).exactly(0).times
|
||||
listener.contact_updated(contact_updated_event)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when webhook is configured and there is no changed attributes' do
|
||||
let(:changed_attributes) { {} }
|
||||
|
||||
it 'triggers webhook' do
|
||||
create(:webhook, account: account)
|
||||
expect(WebhookJob).to receive(:perform_later).exactly(0).times
|
||||
listener.contact_updated(contact_updated_event)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when webhook is configured and there are changed attributes' do
|
||||
it 'triggers webhook' do
|
||||
webhook = create(:webhook, account: account)
|
||||
expect(WebhookJob).to receive(:perform_later).with(
|
||||
webhook.url,
|
||||
contact.webhook_data.merge(
|
||||
event: 'contact_updated',
|
||||
changed_attributes: [{ 'name' => { :current_value => 'Jane Doe', :previous_value => 'Jane' } }]
|
||||
)
|
||||
).once
|
||||
listener.contact_updated(contact_updated_event)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,6 +14,8 @@ properties:
|
||||
"conversation_created",
|
||||
"conversation_status_changed",
|
||||
"conversation_updated",
|
||||
"contact_created",
|
||||
"contact_updated",
|
||||
"message_created",
|
||||
"message_updated",
|
||||
"webwidget_triggered"
|
||||
|
||||
@@ -5264,6 +5264,8 @@
|
||||
"conversation_created",
|
||||
"conversation_status_changed",
|
||||
"conversation_updated",
|
||||
"contact_created",
|
||||
"contact_updated",
|
||||
"message_created",
|
||||
"message_updated",
|
||||
"webwidget_triggered"
|
||||
|
||||
Reference in New Issue
Block a user