diff --git a/app/models/bot/smooch.rb b/app/models/bot/smooch.rb index e85a593db2..4782adbb93 100644 --- a/app/models/bot/smooch.rb +++ b/app/models/bot/smooch.rb @@ -1075,7 +1075,7 @@ def self.refresh_smooch_menu_timeout(message, app_id) uid = message['authorId'] time = Time.now.to_f Rails.cache.write("smooch:last_message_from_user:#{uid}", time) - self.delay_for(15.minutes, { queue: 'smooch' }).timeout_smooch_menu(time, message, app_id, RequestStore.store[:smooch_bot_provider]) + self.delay_for(5.minutes, { queue: 'smooch' }).timeout_smooch_menu(time, message, app_id, RequestStore.store[:smooch_bot_provider]) end def self.timeout_smooch_menu(time, message, app_id, provider) diff --git a/app/models/concerns/smooch_messages.rb b/app/models/concerns/smooch_messages.rb index a77a2edf09..c537c59fa9 100644 --- a/app/models/concerns/smooch_messages.rb +++ b/app/models/concerns/smooch_messages.rb @@ -286,7 +286,7 @@ def handle_bundle_messages(type, list, last, app_id, annotated, send_message = t if ['timeout_requests', 'menu_options_requests', 'resource_requests', 'relevant_search_result_requests', 'timeout_search_requests'].include?(type) key = "smooch:banned:#{bundle['authorId']}" if Rails.cache.read(key).nil? - [annotated].flatten.uniq.each { |a| self.save_message_later(bundle, app_id, type, a) } + [annotated].flatten.uniq.each_with_index { |a, i| self.save_message_later(bundle, app_id, type, a, i * 10) } end end end @@ -317,12 +317,12 @@ def supported_message?(message) ret end - def save_message_later(message, app_id, request_type = 'default_requests', annotated = nil) + def save_message_later(message, app_id, request_type = 'default_requests', annotated = nil, interval = 0) mapping = { 'siege' => 'siege' } queue = RequestStore.store[:smooch_bot_queue].to_s queue = queue.blank? ? 'smooch' : (mapping[queue] || 'smooch') type = (message['type'] == 'text' && !message['text'][/https?:\/\/[^\s]+/, 0].blank?) ? 'link' : message['type'] - SmoochWorker.set(queue: queue).perform_in(1.second, message.to_json, type, app_id, request_type, YAML.dump(annotated)) + SmoochWorker.set(queue: queue).perform_in(1.second + interval.seconds, message.to_json, type, app_id, request_type, YAML.dump(annotated)) end def default_archived_flag @@ -370,8 +370,9 @@ def create_smooch_request(annotated, message, app_id, author) fields = { smooch_data: message.merge({ app_id: app_id }).to_json } result = self.smooch_api_get_messages(app_id, message['authorId']) fields[:smooch_conversation_id] = result.conversation.id unless result.nil? || result.conversation.nil? + fields[:smooch_message_id] = message['_id'] self.create_smooch_annotations(annotated, author, fields) - # update channel values for ProjectMedia items + # Update channel values for ProjectMedia items if annotated.class.name == 'ProjectMedia' channel_value = self.get_smooch_channel(message) unless channel_value.blank? @@ -407,7 +408,11 @@ def create_smooch_annotations(annotated, author, fields, attach_to = false) a.skip_notifications = true a.disable_es_callbacks = Rails.env.to_s == 'test' a.set_fields = fields.to_json - a.save! + begin + a.save! + rescue ActiveRecord::RecordNotUnique + # Don't save a duplicate request + end User.current = current_user end diff --git a/app/models/concerns/smooch_search.rb b/app/models/concerns/smooch_search.rb index 083f000ad0..6774209fc5 100644 --- a/app/models/concerns/smooch_search.rb +++ b/app/models/concerns/smooch_search.rb @@ -247,15 +247,16 @@ def send_search_results_to_whatsapp_user(uid, reports, app_id) # Expires after the time to give feedback is expired Rails.cache.write("smooch:user_search_bundle:#{uid}:#{search_id}", self.list_of_bundled_messages_from_user(uid), expires_in: 20.minutes) self.clear_user_bundled_messages(uid) - reports.each do |report| + reports.each_with_index do |report, i| text = report.report_design_text if report.report_design_field_value('use_text_message') image_url = report.report_design_image_url if report.report_design_field_value('use_visual_card') options = [{ - value: { project_media_id: report.annotated_id, keyword: 'search_result_is_relevant', search_id: search_id }.to_json, + value: { project_media_id: report.annotated_id, keyword: 'search_result_is_relevant', search_id: search_id, index: i }.to_json, label: '👍' }] self.send_message_to_user_with_buttons(uid, text || '-', options, image_url, 'search_result') # "text" is mandatory for WhatsApp interactive messages - self.delay_for(15.minutes, { queue: 'smooch_priority' }).timeout_if_no_feedback_is_given_to_search_result(app_id, uid, search_id, report.annotated_id) + # Schedule each timeout with some interval between them just to avoid race conditions that could create duplicate media + self.delay_for((5 + i).minutes, { queue: 'smooch_priority' }).timeout_if_no_feedback_is_given_to_search_result(app_id, uid, search_id, report.annotated_id) end end @@ -313,8 +314,10 @@ def search_result_button_click_callback(message, uid, app_id, workflow, language result = ProjectMedia.find(payload['project_media_id']) bundle = Rails.cache.read("smooch:user_search_bundle:#{uid}:#{payload['search_id']}").to_a unless bundle.empty? + # Give some interval just to avoid race conditions if the user gives feedback too fast + interval = payload['index'].to_i * 10 Rails.cache.write("smooch:user_search_bundle:#{uid}:#{payload['search_id']}:#{result.id}", Time.now.to_i) # Store that the user has given feedback to this search result - self.delay_for(1.seconds, { queue: 'smooch', retry: false }).bundle_messages(uid, message['_id'], app_id, 'relevant_search_result_requests', [result], true, bundle) + self.delay_for((interval + 1).seconds, { queue: 'smooch', retry: false }).bundle_messages(uid, message['_id'], app_id, 'relevant_search_result_requests', [result], true, bundle) self.send_final_message_to_user(uid, self.get_custom_string('search_result_is_relevant', language), workflow, language) end end diff --git a/db/migrate/20231026162554_add_smooch_message_id_field.rb b/db/migrate/20231026162554_add_smooch_message_id_field.rb new file mode 100644 index 0000000000..0d4fb0f6bd --- /dev/null +++ b/db/migrate/20231026162554_add_smooch_message_id_field.rb @@ -0,0 +1,11 @@ +class AddSmoochMessageIdField < ActiveRecord::Migration[6.1] + require 'sample_data' + include SampleData + + def change + at = DynamicAnnotation::AnnotationType.where(annotation_type: 'smooch').last + ft = DynamicAnnotation::FieldType.where(field_type: 'text').last || create_field_type(field_type: 'text', label: 'Text') + create_field_instance annotation_type_object: at, name: 'smooch_message_id', label: 'Message Id', field_type_object: ft, optional: true + execute %{CREATE UNIQUE INDEX smooch_request_message_id_unique_id ON dynamic_annotation_fields (value) WHERE field_name = 'smooch_message_id' AND value <> '' AND value <> '""'} + end +end