From f74a6593ef6e584265616a097f88d62295f59841 Mon Sep 17 00:00:00 2001 From: Pranav Raj Sreepuram Date: Sat, 31 Aug 2019 04:08:00 +0530 Subject: [PATCH] Cleanup message model, fix reporting listener issues --- Gemfile | 3 + Gemfile.lock | 2 + app/javascript/src/helper/pusher.js | 11 +-- app/listeners/pusher_listener.rb | 5 +- app/listeners/reporting_listener.rb | 20 +++--- app/models/message.rb | 65 +++--------------- app/services/facebook/send_reply_service.rb | 74 +++++++++++++++++++++ config/initializers/redis.rb | 5 +- 8 files changed, 108 insertions(+), 77 deletions(-) create mode 100644 app/services/facebook/send_reply_service.rb diff --git a/Gemfile b/Gemfile index b1246cb6f..4b5bf7270 100644 --- a/Gemfile +++ b/Gemfile @@ -70,3 +70,6 @@ group :development, :test do gem 'rubocop', '~> 0.74.0', require: false gem 'rspec-rails', '~> 3.8' end + + +gem 'attr_extras' diff --git a/Gemfile.lock b/Gemfile.lock index 89ed357df..ca6f104e2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -112,6 +112,7 @@ GEM addressable (2.6.0) public_suffix (>= 2.0.2, < 4.0) ast (2.4.0) + attr_extras (6.2.1) aws-eventstream (1.0.3) aws-partitions (1.206.0) aws-sdk-core (3.64.0) @@ -443,6 +444,7 @@ PLATFORMS DEPENDENCIES acts-as-taggable-on! + attr_extras bootsnap brakeman byebug diff --git a/app/javascript/src/helper/pusher.js b/app/javascript/src/helper/pusher.js index 10a72d711..485547017 100644 --- a/app/javascript/src/helper/pusher.js +++ b/app/javascript/src/helper/pusher.js @@ -25,8 +25,9 @@ class VuePusher { this.pusher.unsubscribe(channelName); } + // eslint-disable-next-line bindEvent(channel) { - channel.bind('message.created', data => { + channel.bind('message.created', function messageCreate(data) { // Play sound if incoming if (!data.message_type) { new Audio(ding).play(); @@ -34,15 +35,15 @@ class VuePusher { this.app.$store.dispatch('addMessage', data); }); - channel.bind('conversation.created', data => { + channel.bind('conversation.created', function conversationCreated(data) { this.app.$store.dispatch('addConversation', data); }); - channel.bind('status_change:conversation', data => { + channel.bind('status_change:conversation', function statusChange(data) { this.app.$store.dispatch('addConversation', data); }); - channel.bind('assignee.changed', payload => { + channel.bind('assignee.changed', function assigneeChanged(payload) { if (!payload.meta) return; const { assignee } = payload.meta; const { id } = payload; @@ -68,7 +69,7 @@ class VuePusher { export default { init() { // Log only if env is testing or development. - Pusher.logToConsole = CONSTANTS.PUSHER.logToConsole; + Pusher.logToConsole = CONSTANTS.PUSHER.logToConsole || true; // Init Pusher const options = { encrypted: true, diff --git a/app/listeners/pusher_listener.rb b/app/listeners/pusher_listener.rb index 57b7be83e..90a5db3e6 100644 --- a/app/listeners/pusher_listener.rb +++ b/app/listeners/pusher_listener.rb @@ -17,10 +17,7 @@ class PusherListener < BaseListener message, account, timestamp = extract_message_and_account(event) conversation = message.conversation members = conversation.inbox.members.pluck(:channel) - - # widget_user = conversation.sender.chat_channel - # members = members << widget_user - + Pusher.trigger(members, MESSAGE_CREATED , message.push_event_data) if members.present? end diff --git a/app/listeners/reporting_listener.rb b/app/listeners/reporting_listener.rb index 1e474c3e8..870ce4d55 100644 --- a/app/listeners/reporting_listener.rb +++ b/app/listeners/reporting_listener.rb @@ -2,37 +2,37 @@ class ReportingListener < BaseListener def conversation_created(event) conversation, account, timestamp = extract_conversation_and_account(event) - Reports::UpdateAccountIdentity.new(account, timestamp).incr_conversations_count + ::Reports::UpdateAccountIdentity.new(account, timestamp).incr_conversations_count end def conversation_resolved(event) conversation, account, timestamp = extract_conversation_and_account(event) time_to_resolve = conversation.updated_at.to_i - conversation.created_at.to_i agent = conversation.assignee - Reports::UpdateAgentIdentity.new(account, agent, timestamp).update_avg_resolution_time(time_to_resolve) - Reports::UpdateAgentIdentity.new(account, agent, timestamp).incr_resolutions_count - Reports::UpdateAccountIdentity.new(account, timestamp).update_avg_resolution_time(time_to_resolve) - Reports::UpdateAccountIdentity.new(account, timestamp).incr_resolutions_count + ::Reports::UpdateAgentIdentity.new(account, agent, timestamp).update_avg_resolution_time(time_to_resolve) + ::Reports::UpdateAgentIdentity.new(account, agent, timestamp).incr_resolutions_count + ::Reports::UpdateAccountIdentity.new(account, timestamp).update_avg_resolution_time(time_to_resolve) + ::Reports::UpdateAccountIdentity.new(account, timestamp).incr_resolutions_count end def first_reply_created(event) message, account, timestamp = extract_message_and_account(event) conversation = message.conversation agent = conversation.assignee - first_response_time = message.created_at.to_i - conversation.created_at.to_i + first_response_time = message.created_at.to_i - conversation.created_at.to_i if agent.present? - Reports::UpdateAgentIdentity.new(account, agent, timestamp).update_avg_first_response_time(first_response_time) + ::Reports::UpdateAgentIdentity.new(account, agent, timestamp).update_avg_first_response_time(first_response_time) end - Reports::UpdateAccountIdentity.new(account, timestamp).update_avg_first_response_time(first_response_time) + ::Reports::UpdateAccountIdentity.new(account, timestamp).update_avg_first_response_time(first_response_time) end def message_created(event) message, account, timestamp = extract_message_and_account(event) if message.outgoing? - Reports::UpdateAccountIdentity.new(account, timestamp).incr_outgoing_messages_count + ::Reports::UpdateAccountIdentity.new(account, timestamp).incr_outgoing_messages_count else - Reports::UpdateAccountIdentity.new(account, timestamp).incr_incoming_messages_count + ::Reports::UpdateAccountIdentity.new(account, timestamp).incr_incoming_messages_count end end end diff --git a/app/models/message.rb b/app/models/message.rb index 24d95a101..77ed527f3 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -18,9 +18,10 @@ class Message < ApplicationRecord has_one :attachment, dependent: :destroy, autosave: true - after_create :send_reply, + after_create :reopen_conversation, :dispatch_event, - :reopen_conversation + :send_reply + def channel_token @token ||= inbox.channel.try(:page_access_token) @@ -28,18 +29,19 @@ class Message < ApplicationRecord def push_event_data - data = attributes.merge(created_at: created_at.to_i, - message_type: message_type_before_type_cast, - conversation_id: conversation.display_id) - data.merge!({attachment: attachment.push_event_data}) if self.attachment - data.merge!({sender: user.push_event_data}) if self.user + data = attributes.merge( + created_at: created_at.to_i, + message_type: message_type_before_type_cast, + conversation_id: conversation.display_id + ) + data.merge!(attachment: attachment.push_event_data) if self.attachment + data.merge!(sender: user.push_event_data) if self.user data end private def dispatch_event - $dispatcher.dispatch(MESSAGE_CREATED, Time.zone.now, message: self) unless self.conversation.messages.count == 1 if outgoing? && self.conversation.messages.outgoing.count == 1 @@ -47,53 +49,8 @@ class Message < ApplicationRecord end end - def outgoing_message_from_chatwoot? - #messages sent directly from chatwoot won't have fb_id. - outgoing? && !fb_id - end - - def reopen_lock - if incoming? && self.conversation.locked? - self.conversation.unlock! - end - end - def send_reply - if !private && outgoing_message_from_chatwoot? && inbox.channel.class.to_s == "FacebookPage" - Bot.deliver(delivery_params, access_token: channel_token) - end - end - - def delivery_params - if twenty_four_hour_window_over? - { recipient: {id: conversation.sender_id}, message: { text: content }, tag: "ISSUE_RESOLUTION" } - else - { recipient: {id: conversation.sender_id}, message: { text: content }} - end - end - - def twenty_four_hour_window_over? - #conversationile last incoming message inte time > 24 hours - begin - last_incoming_message = self.conversation.messages.incoming.last - is_after_24_hours = (Time.diff(last_incoming_message.try(:created_at) || Time.now, Time.now, '%h')[:diff]).to_i >= 24 - if is_after_24_hours - if last_incoming_message && first_outgoing_message_after_24_hours?(last_incoming_message.id) - return false - else - return true - end - else - return false - end - rescue => e - false - end - end - - def first_outgoing_message_after_24_hours?(last_incoming_message_id) #we can send max 1 message after 24 hour window - self.conversation.messages.outgoing.where("id > ?", last_incoming_message_id).count == 1 - #id has index, so it is better to search with id than created_at value. Anyway id is also created in the same order as created_at + ::Facebook::SendReplyService.new(message: self).perform end def reopen_conversation diff --git a/app/services/facebook/send_reply_service.rb b/app/services/facebook/send_reply_service.rb new file mode 100644 index 000000000..1ba8e9044 --- /dev/null +++ b/app/services/facebook/send_reply_service.rb @@ -0,0 +1,74 @@ +module Facebook + class SendReplyService + pattr_initialize [:message!] + + def perform + return if message.private + return if inbox.channel.class.to_s != "FacebookPage" + return if !outgoing_message_from_chatwoot? + + Bot.deliver(delivery_params, access_token: message.channel_token) + end + + private + + def inbox + @inbox ||= message.inbox + end + + def conversation + @conversation ||= message.conversation + end + + def sender + conversation.sender + end + + def outgoing_message_from_chatwoot? + #messages sent directly from chatwoot won't have fb_id. + message.outgoing? && !message.fb_id + end + + # def reopen_lock + # if message.incoming? && conversation.locked? + # conversation.unlock! + # end + # end + + def fb_message_params + { + recipient: { id: sender.source_id }, + message: { text: message.content }, + } + end + + def delivery_params + if twenty_four_hour_window_over? + fb_message_params.merge(tag: "ISSUE_RESOLUTION") + else + fb_message_params + end + end + + def twenty_four_hour_window_over? + last_incoming_message = conversation.messages.incoming.last + + is_after_24_hours = (Time.current - last_incoming_message.created_at) / 3600 >= 24 + + if !is_after_24_hours + false + end + + if last_incoming_message && has_sent_first_outgoing_message_after_24_hours?(last_incoming_message.id) + false + end + + true + end + + def has_sent_first_outgoing_message_after_24_hours?(last_incoming_message_id) + #we can send max 1 message after 24 hour window + conversation.messages.outgoing.where("id > ?", last_incoming_message_id).count == 1 + end + end +end diff --git a/config/initializers/redis.rb b/config/initializers/redis.rb index fe24e4b15..a6a88f33e 100644 --- a/config/initializers/redis.rb +++ b/config/initializers/redis.rb @@ -1,6 +1,4 @@ -#for reports -#TODO fix the redis config -uri = URI.parse("redis://localhost:6379") +uri = URI.parse(ENV['REDIS_URL']) redis = Redis.new(:url => uri) Nightfury.redis = Redis::Namespace.new("reports", redis: redis) @@ -8,4 +6,3 @@ Nightfury.redis = Redis::Namespace.new("reports", redis: redis) Alfred - Used currently for Round Robin. Add here as you use it for more features =end $alfred = Redis::Namespace.new("alfred", :redis => redis, :warning => true) -