From 791d90c6b71d94124a93fc85aaa8c5094f9b7613 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Mon, 22 Nov 2021 23:32:17 +0530 Subject: [PATCH] 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 Co-authored-by: Muhsin Keloth --- app/actions/contact_merge_action.rb | 5 +- app/channels/room_channel.rb | 2 +- app/controllers/widgets_controller.rb | 10 ++-- app/finders/conversation_finder.rb | 2 +- .../assets/scss/_utility-helpers.scss | 8 +++ .../conversation/ConversationHeader.vue | 15 ++++-- .../i18n/locale/en/conversation.json | 1 + .../conversation/contact/ConversationForm.vue | 12 ++--- app/javascript/widget/helpers/actionCable.js | 17 +----- .../widget/helpers/campaignHelper.js | 18 ++++--- .../helpers/specs/campaignHelper.spec.js | 54 +++++++++++++++++++ .../widget/store/modules/contacts.js | 7 +-- .../store/modules/conversation/actions.js | 7 +-- .../widget/store/modules/message.js | 6 +-- app/listeners/action_cable_listener.rb | 12 +++-- app/models/concerns/pubsubable.rb | 6 +++ app/models/contact.rb | 2 +- app/models/contact_inbox.rb | 3 ++ .../conversations/event_data_presenter.rb | 6 ++- .../partials/_conversation.json.jbuilder | 1 + .../v1/widget/configs/create.json.jbuilder | 2 +- .../v1/inboxes/contacts/create.json.jbuilder | 1 + .../v1/inboxes/contacts/show.json.jbuilder | 1 + .../v1/inboxes/contacts/update.json.jbuilder | 1 + .../api/v1/models/_contact.json.jbuilder | 1 - app/views/widgets/show.html.erb | 2 +- config/app.yml | 2 +- ...1012_add_pub_sub_token_to_contact_inbox.rb | 6 +++ db/schema.rb | 4 +- package.json | 2 +- spec/channels/room_channel_spec.rb | 6 +-- .../api/v1/widget/configs_controller_spec.rb | 2 +- .../api/v1/inbox/contacts_controller_spec.rb | 2 +- spec/listeners/action_cable_listener_spec.rb | 18 ++++++- spec/models/contact_inbox_spec.rb | 40 ++++++++++++++ spec/models/contact_spec.rb | 16 ------ spec/models/conversation_spec.rb | 3 +- .../event_data_presenter_spec.rb | 3 +- 38 files changed, 211 insertions(+), 95 deletions(-) create mode 100644 db/migrate/20211122061012_add_pub_sub_token_to_contact_inbox.rb create mode 100644 spec/models/contact_inbox_spec.rb diff --git a/app/actions/contact_merge_action.rb b/app/actions/contact_merge_action.rb index d31b6a367..9d58ef207 100644 --- a/app/actions/contact_merge_action.rb +++ b/app/actions/contact_merge_action.rb @@ -48,11 +48,10 @@ class ContactMergeAction # 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]) + Rails.configuration.dispatcher.dispatch(CONTACT_MERGED, Time.zone.now, contact: @base_contact, + tokens: [@base_contact.contact_inboxes.filter_map(&:pubsub_token)]) @base_contact.update!(merged_attributes) end end diff --git a/app/channels/room_channel.rb b/app/channels/room_channel.rb index ab3af0c92..b3c597770 100644 --- a/app/channels/room_channel.rb +++ b/app/channels/room_channel.rb @@ -31,7 +31,7 @@ class RoomChannel < ApplicationCable::Channel def current_user @current_user ||= if params[:user_id].blank? - Contact.find_by!(pubsub_token: @pubsub_token) + ContactInbox.find_by!(pubsub_token: @pubsub_token).contact else User.find_by!(pubsub_token: @pubsub_token, id: params[:user_id]) end diff --git a/app/controllers/widgets_controller.rb b/app/controllers/widgets_controller.rb index f19a24888..29c1f97f9 100644 --- a/app/controllers/widgets_controller.rb +++ b/app/controllers/widgets_controller.rb @@ -29,21 +29,21 @@ class WidgetsController < ActionController::Base def set_contact return if @auth_token_params[:source_id].nil? - contact_inbox = ::ContactInbox.find_by( + @contact_inbox = ::ContactInbox.find_by( inbox_id: @web_widget.inbox.id, source_id: @auth_token_params[:source_id] ) - @contact = contact_inbox ? contact_inbox.contact : nil + @contact = @contact_inbox ? @contact_inbox.contact : nil end def build_contact return if @contact.present? - contact_inbox = @web_widget.create_contact_inbox(additional_attributes) - @contact = contact_inbox.contact + @contact_inbox = @web_widget.create_contact_inbox(additional_attributes) + @contact = @contact_inbox.contact - payload = { source_id: contact_inbox.source_id, inbox_id: @web_widget.inbox.id } + payload = { source_id: @contact_inbox.source_id, inbox_id: @web_widget.inbox.id } @token = ::Widget::TokenService.new(payload: payload).generate_token end diff --git a/app/finders/conversation_finder.rb b/app/finders/conversation_finder.rb index a0dda66ea..f2641dde0 100644 --- a/app/finders/conversation_finder.rb +++ b/app/finders/conversation_finder.rb @@ -121,7 +121,7 @@ class ConversationFinder def conversations @conversations = @conversations.includes( - :taggings, :inbox, { assignee: { avatar_attachment: [:blob] } }, { contact: { avatar_attachment: [:blob] } }, :team + :taggings, :inbox, { assignee: { avatar_attachment: [:blob] } }, { contact: { avatar_attachment: [:blob] } }, :team, :contact_inbox ) @conversations.latest.page(current_page) end diff --git a/app/javascript/dashboard/assets/scss/_utility-helpers.scss b/app/javascript/dashboard/assets/scss/_utility-helpers.scss index 8785f1313..1072a0878 100644 --- a/app/javascript/dashboard/assets/scss/_utility-helpers.scss +++ b/app/javascript/dashboard/assets/scss/_utility-helpers.scss @@ -2,6 +2,10 @@ margin-right: var(--space-small); } +.margin-right-smaller { + margin-right: var(--space-smaller); +} + .fs-small { font-size: var(--font-size-small); } @@ -42,3 +46,7 @@ .bg-white { background-color: var(--white); } + +.text-y-800 { + color: var(--y-800); +} diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationHeader.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationHeader.vue index bdb917695..22989f36f 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationHeader.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationHeader.vue @@ -10,7 +10,12 @@ />

- {{ currentContact.name }} + {{ currentContact.name }} +

@@ -73,11 +78,15 @@ export default { uiFlags: 'inboxAssignableAgents/getUIFlags', currentChat: 'getSelectedChat', }), - chatMetadata() { return this.chat.meta; }, - + isHMACVerified() { + if (!this.isAWebWidgetInbox) { + return true; + } + return this.chatMetadata.hmac_verified; + }, currentContact() { return this.$store.getters['contacts/getContact']( this.chat.meta.sender.id diff --git a/app/javascript/dashboard/i18n/locale/en/conversation.json b/app/javascript/dashboard/i18n/locale/en/conversation.json index a50e8cb16..9e2e3ea08 100644 --- a/app/javascript/dashboard/i18n/locale/en/conversation.json +++ b/app/javascript/dashboard/i18n/locale/en/conversation.json @@ -1,6 +1,7 @@ { "CONVERSATION": { "404": "Please select a conversation from left pane", + "UNVERIFIED_SESSION": "The identity of this user is not verified", "NO_MESSAGE_1": "Uh oh! Looks like there are no messages from customers in your inbox.", "NO_MESSAGE_2": " to send a message to your page!", "NO_INBOX_1": "Hola! Looks like you haven't added any inboxes yet.", diff --git a/app/javascript/dashboard/routes/dashboard/conversation/contact/ConversationForm.vue b/app/javascript/dashboard/routes/dashboard/conversation/contact/ConversationForm.vue index 22acd84e5..b0251df18 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/contact/ConversationForm.vue +++ b/app/javascript/dashboard/routes/dashboard/conversation/contact/ConversationForm.vue @@ -41,17 +41,17 @@
-
+
-