From 5319af3dfce9d17374851ae4cf817d77811fd378 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 31 Aug 2021 15:30:18 +0530 Subject: [PATCH] chore: Merge contact copy over information (#2812) fixes: #2767, #2773 Co-authored-by: Nithin David <1277421+nithindavid@users.noreply.github.com> --- app/actions/contact_merge_action.rb | 16 ++++++++-- app/javascript/widget/helpers/actionCable.js | 31 +++++++++++++------- app/listeners/action_cable_listener.rb | 7 +++++ app/models/contact.rb | 2 ++ lib/events/types.rb | 1 + spec/actions/contact_merge_action_spec.rb | 22 ++++++++++++-- 6 files changed, 64 insertions(+), 15 deletions(-) diff --git a/app/actions/contact_merge_action.rb b/app/actions/contact_merge_action.rb index 3a3ef11ed..f20e2ffb4 100644 --- a/app/actions/contact_merge_action.rb +++ b/app/actions/contact_merge_action.rb @@ -1,4 +1,5 @@ class ContactMergeAction + include Events::Types pattr_initialize [:account!, :base_contact!, :mergee_contact!] def perform @@ -11,7 +12,7 @@ class ContactMergeAction merge_conversations merge_messages merge_contact_inboxes - remove_mergee_contact + merge_and_remove_mergee_contact end @base_contact end @@ -40,7 +41,18 @@ class ContactMergeAction ContactInbox.where(contact_id: @mergee_contact.id).update(contact_id: @base_contact.id) end - def remove_mergee_contact + def merge_and_remove_mergee_contact + mergable_attribute_keys = %w[identifier name email phone_number custom_attributes] + base_contact_attributes = base_contact.attributes.slice(*mergable_attribute_keys).compact_blank + mergee_contact_attributes = mergee_contact.attributes.slice(*mergable_attribute_keys).compact_blank + + # attributes in base contact are given preference + merged_attributes = mergee_contact_attributes.deep_merge(base_contact_attributes) + # retaining old pubsub token to notify the contacts that are listening + mergee_pubsub_token = mergee_contact.pubsub_token + @mergee_contact.destroy! + Rails.configuration.dispatcher.dispatch(CONTACT_MERGED, Time.zone.now, contact: @base_contact, tokens: [mergee_pubsub_token]) + @base_contact.update!(merged_attributes) end end diff --git a/app/javascript/widget/helpers/actionCable.js b/app/javascript/widget/helpers/actionCable.js index 9b6cf2211..32bdd644f 100644 --- a/app/javascript/widget/helpers/actionCable.js +++ b/app/javascript/widget/helpers/actionCable.js @@ -10,9 +10,22 @@ class ActionCableConnector extends BaseActionCableConnector { 'conversation.typing_off': this.onTypingOff, 'conversation.status_changed': this.onStatusChange, 'presence.update': this.onPresenceUpdate, + 'contact.merged': this.onContactMerge, }; } + static refreshConnector = pubsubToken => { + if (!pubsubToken || window.chatwootPubsubToken === pubsubToken) { + return; + } + window.chatwootPubsubToken = pubsubToken; + window.actionCable.disconnect(); + window.actionCable = new ActionCableConnector( + window.WOOT_WIDGET, + window.chatwootPubsubToken + ); + }; + onStatusChange = data => { this.app.$store.dispatch('conversationAttributes/update', data); }; @@ -33,6 +46,11 @@ class ActionCableConnector extends BaseActionCableConnector { this.app.$store.dispatch('agent/updatePresence', data.users); }; + onContactMerge = data => { + const { pubsub_token: pubsubToken } = data; + ActionCableConnector.refreshConnector(pubsubToken); + }; + onTypingOn = () => { this.clearTimer(); this.app.$store.dispatch('conversation/toggleAgentTyping', { @@ -63,16 +81,7 @@ class ActionCableConnector extends BaseActionCableConnector { }; } -export const refreshActionCableConnector = pubsubToken => { - if (!pubsubToken || window.chatwootPubsubToken === pubsubToken) { - return; - } - window.chatwootPubsubToken = pubsubToken; - window.actionCable.disconnect(); - window.actionCable = new ActionCableConnector( - window.WOOT_WIDGET, - window.chatwootPubsubToken - ); -}; +export const refreshActionCableConnector = + ActionCableConnector.refreshConnector; export default ActionCableConnector; diff --git a/app/listeners/action_cable_listener.rb b/app/listeners/action_cable_listener.rb index 3efae0b30..dfedc5ba7 100644 --- a/app/listeners/action_cable_listener.rb +++ b/app/listeners/action_cable_listener.rb @@ -104,6 +104,13 @@ class ActionCableListener < BaseListener broadcast(account, tokens, CONTACT_UPDATED, contact.push_event_data) end + def contact_merged(event) + contact, account = extract_contact_and_account(event) + tokens = event.data[:tokens] + + broadcast(account, tokens, CONTACT_MERGED, contact.push_event_data) + end + private def typing_event_listener_tokens(account, conversation, user) diff --git a/app/models/contact.rb b/app/models/contact.rb index 391c0a2bf..b81b520f2 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -77,6 +77,8 @@ class Contact < ApplicationRecord } end + private + def ip_lookup return unless account.feature_enabled?('ip_lookup') diff --git a/lib/events/types.rb b/lib/events/types.rb index 4d027f6f8..c47691cd2 100644 --- a/lib/events/types.rb +++ b/lib/events/types.rb @@ -34,6 +34,7 @@ module Events::Types # contact events CONTACT_CREATED = 'contact.created' CONTACT_UPDATED = 'contact.updated' + CONTACT_MERGED = 'contact.merged' # agent events AGENT_ADDED = 'agent.added' diff --git a/spec/actions/contact_merge_action_spec.rb b/spec/actions/contact_merge_action_spec.rb index 62ff81a52..a00f908fa 100644 --- a/spec/actions/contact_merge_action_spec.rb +++ b/spec/actions/contact_merge_action_spec.rb @@ -4,8 +4,14 @@ describe ::ContactMergeAction do subject(:contact_merge) { described_class.new(account: account, base_contact: base_contact, mergee_contact: mergee_contact).perform } let!(:account) { create(:account) } - let!(:base_contact) { create(:contact, account: account) } - let!(:mergee_contact) { create(:contact, account: account) } + let!(:base_contact) do + create(:contact, identifier: 'base_contact', email: 'old@old.com', phone_number: '', custom_attributes: { val_test: 'old', val_empty_old: '' }, + account: account) + end + let!(:mergee_contact) do + create(:contact, identifier: '', email: 'new@new.com', phone_number: '+12212345', + custom_attributes: { val_test: 'new', val_new: 'new', val_empty_new: '' }, account: account) + end before do 2.times.each do @@ -21,6 +27,18 @@ describe ::ContactMergeAction do expect { mergee_contact.reload }.to raise_error(ActiveRecord::RecordNotFound) end + it 'copies information from mergee contact to base contact' do + contact_merge + base_contact.reload + expect(base_contact.identifier).to eq('base_contact') + expect(base_contact.email).to eq('old@old.com') + expect(base_contact.phone_number).to eq('+12212345') + expect(base_contact.custom_attributes['val_test']).to eq('old') + expect(base_contact.custom_attributes['val_new']).to eq('new') + expect(base_contact.custom_attributes['val_empty_old']).to eq('') + expect(base_contact.custom_attributes['val_empty_new']).to eq('') + end + context 'when base contact and merge contact are same' do it 'does not delete contact' do mergee_contact = base_contact