chore: Migrate PubSub Token to contact inbox (#3434)
At present, the websocket pubsub tokens are present at the contact objects in chatwoot. A better approach would be to have these tokens at the contact_inbox object instead. This helps chatwoot to deliver the websocket events targetted to the specific widget connection, stop contact events from leaking into other chat sessions from the same contact. Fixes #1682 Fixes #1664 Co-authored-by: Pranav Raj S <pranav@chatwoot.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe RoomChannel, type: :channel do
|
||||
let!(:contact) { create(:contact) }
|
||||
let!(:contact_inbox) { create(:contact_inbox) }
|
||||
|
||||
before do
|
||||
stub_connection
|
||||
end
|
||||
|
||||
it 'subscribes to a stream when pubsub_token is provided' do
|
||||
subscribe(pubsub_token: contact.pubsub_token)
|
||||
subscribe(pubsub_token: contact_inbox.pubsub_token)
|
||||
expect(subscription).to be_confirmed
|
||||
expect(subscription).to have_stream_for(contact.pubsub_token)
|
||||
expect(subscription).to have_stream_for(contact_inbox.pubsub_token)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,7 +45,7 @@ RSpec.describe '/api/v1/widget/config', type: :request do
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body)
|
||||
expect(response_data.keys).to include(*response_keys)
|
||||
expect(response_data['contact']['pubsub_token']).to eq(contact.pubsub_token)
|
||||
expect(response_data['contact']['pubsub_token']).to eq(contact_inbox.pubsub_token)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ RSpec.describe 'Public Inbox Contacts API', type: :request do
|
||||
expect(response).to have_http_status(:success)
|
||||
data = JSON.parse(response.body)
|
||||
expect(data['source_id']).to eq contact_inbox.source_id
|
||||
expect(data['pubsub_token']).to eq contact.pubsub_token
|
||||
expect(data['pubsub_token']).to eq contact_inbox.pubsub_token
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -24,7 +24,23 @@ describe ActionCableListener do
|
||||
expect(conversation.inbox.reload.inbox_members.count).to eq(1)
|
||||
|
||||
expect(ActionCableBroadcastJob).to receive(:perform_later).with(
|
||||
[agent.pubsub_token, admin.pubsub_token, conversation.contact.pubsub_token],
|
||||
[agent.pubsub_token, admin.pubsub_token, conversation.contact_inbox.pubsub_token],
|
||||
'message.created',
|
||||
message.push_event_data.merge(account_id: account.id)
|
||||
)
|
||||
listener.message_created(event)
|
||||
end
|
||||
|
||||
it 'sends message to all hmac verified contact inboxes' do
|
||||
# HACK: to reload conversation inbox members
|
||||
expect(conversation.inbox.reload.inbox_members.count).to eq(1)
|
||||
conversation.contact_inbox.update(hmac_verified: true)
|
||||
# creating a non verified contact inbox to ensure the events are not sent to it
|
||||
create(:contact_inbox, contact: conversation.contact, inbox: inbox)
|
||||
verified_contact_inbox = create(:contact_inbox, contact: conversation.contact, inbox: inbox, hmac_verified: true)
|
||||
|
||||
expect(ActionCableBroadcastJob).to receive(:perform_later).with(
|
||||
[agent.pubsub_token, admin.pubsub_token, conversation.contact_inbox.pubsub_token, verified_contact_inbox.pubsub_token],
|
||||
'message.created',
|
||||
message.push_event_data.merge(account_id: account.id)
|
||||
)
|
||||
|
||||
40
spec/models/contact_inbox_spec.rb
Normal file
40
spec/models/contact_inbox_spec.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ContactInbox do
|
||||
describe 'pubsub_token' do
|
||||
let(:contact_inbox) { create(:contact_inbox) }
|
||||
|
||||
it 'gets created on object create' do
|
||||
obj = contact_inbox
|
||||
expect(obj.pubsub_token).not_to eq(nil)
|
||||
end
|
||||
|
||||
it 'does not get updated on object update' do
|
||||
obj = contact_inbox
|
||||
old_token = obj.pubsub_token
|
||||
obj.update(source_id: '234234323')
|
||||
expect(obj.pubsub_token).to eq(old_token)
|
||||
end
|
||||
|
||||
it 'backfills pubsub_token on call for older objects' do
|
||||
obj = create(:contact_inbox)
|
||||
# to replicate an object with out pubsub_token
|
||||
# rubocop:disable Rails/SkipsModelValidations
|
||||
obj.update_column(:pubsub_token, nil)
|
||||
# rubocop:enable Rails/SkipsModelValidations
|
||||
|
||||
obj.reload
|
||||
|
||||
# ensure the column is nil in database
|
||||
results = ActiveRecord::Base.connection.execute('Select * from contact_inboxes;')
|
||||
expect(results.first['pubsub_token']).to eq(nil)
|
||||
|
||||
new_token = obj.pubsub_token
|
||||
obj.update(source_id: '234234323')
|
||||
# the generated token shoul be persisted in db
|
||||
expect(obj.pubsub_token).to eq(new_token)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -11,20 +11,4 @@ RSpec.describe Contact do
|
||||
it { is_expected.to belong_to(:account) }
|
||||
it { is_expected.to have_many(:conversations).dependent(:destroy) }
|
||||
end
|
||||
|
||||
describe 'pubsub_token' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it 'gets created on object create' do
|
||||
obj = user
|
||||
expect(obj.pubsub_token).not_to eq(nil)
|
||||
end
|
||||
|
||||
it 'does not get updated on object update' do
|
||||
obj = user
|
||||
old_token = obj.pubsub_token
|
||||
obj.update(name: 'test')
|
||||
expect(obj.pubsub_token).to eq(old_token)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -375,7 +375,8 @@ RSpec.describe Conversation, type: :model do
|
||||
additional_attributes: {},
|
||||
meta: {
|
||||
sender: conversation.contact.push_event_data,
|
||||
assignee: conversation.assignee
|
||||
assignee: conversation.assignee,
|
||||
hmac_verified: conversation.contact_inbox.hmac_verified
|
||||
},
|
||||
id: conversation.display_id,
|
||||
messages: [],
|
||||
|
||||
@@ -12,7 +12,8 @@ RSpec.describe Conversations::EventDataPresenter do
|
||||
additional_attributes: {},
|
||||
meta: {
|
||||
sender: conversation.contact.push_event_data,
|
||||
assignee: conversation.assignee
|
||||
assignee: conversation.assignee,
|
||||
hmac_verified: conversation.contact_inbox.hmac_verified
|
||||
},
|
||||
id: conversation.display_id,
|
||||
messages: [],
|
||||
|
||||
Reference in New Issue
Block a user