Skip to content

Commit

Permalink
Merge pull request #1645 from tactilenews/360dialog_spike
Browse files Browse the repository at this point in the history
  • Loading branch information
mattwr18 authored Nov 1, 2023
2 parents 2f1c7c4 + 13ec520 commit beee331
Show file tree
Hide file tree
Showing 36 changed files with 2,859 additions and 337 deletions.
4 changes: 4 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ THREEMARB_PRIVATE=
# POSTMARK_TRANSACTIONAL_STREAM=outbound
# DOCKER_IMAGE_TAG=
# SENTRY_DSN=
#
# THREE_SIXTY_DIALOG_PARTNER_ID=
# THREE_SIXTY_DIALOG_PARTNER_USERNAME=
# THREE_SIXTY_DIALOG_PARTNER_PASSWORD=
224 changes: 115 additions & 109 deletions ansible/inventories/staging/host_vars/staging.yml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions ansible/roles/installation/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
TWILIO_AUTH_TOKEN: "{{ rails.twilio.auth_token }}"
TWILIO_API_KEY_SID: "{{ rails.twilio.api_key.sid }}"
TWILIO_API_KEY_SECRET: "{{ rails.twilio.api_key.secret }}"
THREE_SIXTY_DIALOG_PARTNER_ID: "{{ rails.three_sixty_dialog.partner.id }}"
THREE_SIXTY_DIALOG_PARTNER_USERNAME: "{{ rails.three_sixty_dialog.partner.username }}"
THREE_SIXTY_DIALOG_PARTNER_PASSWORD: "{{ rails.three_sixty_dialog.partner.password }}"

community.general.docker_compose:
project_src: /home/ansible
build: no
Expand Down
91 changes: 7 additions & 84 deletions app/adapters/whats_app_adapter/outbound.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,95 +3,18 @@
module WhatsAppAdapter
class Outbound
class << self
def send!(message)
recipient = message&.recipient
return unless contributor_can_receive_messages?(recipient)
delegate :send!, to: :business_solution_provider

if freeform_message_permitted?(recipient)
send_message(recipient, message)
else
send_message_template(recipient, message)
end
end

def send_welcome_message!(contributor)
return unless contributor_can_receive_messages?(contributor)

welcome_message = I18n.t('adapter.whats_app.welcome_message', project_name: Setting.project_name)
WhatsAppAdapter::Outbound::Text.perform_later(recipient: contributor, text: welcome_message)
end

def send_unsupported_content_message!(contributor)
return unless contributor_can_receive_messages?(contributor)

WhatsAppAdapter::Outbound::Text.perform_later(recipient: contributor,
text: I18n.t('adapter.whats_app.unsupported_content_template',
first_name: contributor.first_name,
contact_person: contributor.organization.contact_person.name))
end

def send_more_info_message!(contributor)
return unless contributor_can_receive_messages?(contributor)

text = [Setting.about, "_#{I18n.t('adapter.whats_app.unsubscribe.instructions')}_"].join("\n\n")
WhatsAppAdapter::Outbound::Text.perform_later(recipient: contributor, text: text)
end
delegate :send_welcome_message!, to: :business_solution_provider

def send_unsubsribed_successfully_message!(contributor)
return unless contributor_can_receive_messages?(contributor)
delegate :send_more_info_message!, to: :business_solution_provider

text = [I18n.t('adapter.whats_app.unsubscribe.successful'), "_#{I18n.t('adapter.whats_app.subscribe.instructions')}_"].join("\n\n")
WhatsAppAdapter::Outbound::Text.perform_later(recipient: contributor, text: text)
end

def contributor_can_receive_messages?(recipient)
recipient&.whats_app_phone_number.present?
end

def time_of_day
current_time = Time.current
morning = current_time.change(hour: 6)
day = current_time.change(hour: 11)
evening = current_time.change(hour: 17)
night = current_time.change(hour: 23)

case current_time
when morning..day
'morning'
when day..evening
'day'
when evening..night
'evening'
else
'night'
end
end

def freeform_message_permitted?(recipient)
responding_to_template_message = recipient.whats_app_message_template_responded_at.present? &&
recipient.whats_app_message_template_responded_at > 24.hours.ago
latest_message_received_within_last_24_hours = recipient.replies.first&.created_at.present? &&
recipient.replies.first.created_at > 24.hours.ago
responding_to_template_message || latest_message_received_within_last_24_hours
end

def send_message_template(recipient, message)
recipient.update!(whats_app_message_template_sent_at: Time.current)
text = I18n.t("adapter.whats_app.request_template.new_request_#{time_of_day}_#{rand(1..3)}", first_name: recipient.first_name,
request_title: message.request.title)
WhatsAppAdapter::Outbound::Text.perform_later(recipient: recipient, text: text)
end
delegate :send_unsubsribed_successfully_message!, to: :business_solution_provider

def send_message(recipient, message)
files = message.files
private

if files.blank?
WhatsAppAdapter::Outbound::Text.perform_later(recipient: recipient, text: message.text)
else
files.each_with_index do |file, index|
WhatsAppAdapter::Outbound::File.perform_later(recipient: recipient, text: index.zero? ? message.text : '', file: file)
end
end
def business_solution_provider
Setting.three_sixty_dialog_client_api_key.present? ? WhatsAppAdapter::ThreeSixtyDialogOutbound : WhatsAppAdapter::TwilioOutbound
end
end
end
Expand Down
49 changes: 49 additions & 0 deletions app/adapters/whats_app_adapter/outbound/three_sixty_dialog_file.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

module WhatsAppAdapter
class Outbound
class ThreeSixtyDialogFile < ApplicationJob
queue_as :default

def perform(message_id:, file_id:)
message = Message.find(message_id)
@recipient = message.recipient
@file_id = file_id

url = URI.parse("#{Setting.three_sixty_dialog_whats_app_rest_api_endpoint}/messages")
headers = { 'D360-API-KEY' => Setting.three_sixty_dialog_client_api_key, 'Content-Type' => 'application/json' }
request = Net::HTTP::Post.new(url.to_s, headers)
request.body = payload.to_json
response = Net::HTTP.start(url.host, url.port, use_ssl: true) do |http|
http.request(request)
end
handle_response(response)
end

private

attr_reader :recipient, :file_id

def payload
{
recipient_type: 'individual',
to: recipient.whats_app_phone_number.split('+').last,
type: 'image',
image: {
id: file_id
}
}
end

def handle_response(response)
case response.code.to_i
when 200
Rails.logger.debug 'Great!'
when 400..599
exception = WhatsAppAdapter::ThreeSixtyDialogError.new(error_code: response.code, message: response.body)
ErrorNotifier.report(exception)
end
end
end
end
end
33 changes: 33 additions & 0 deletions app/adapters/whats_app_adapter/outbound/three_sixty_dialog_text.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module WhatsAppAdapter
class Outbound
class ThreeSixtyDialogText < ApplicationJob
queue_as :default

def perform(payload:)
url = URI.parse("#{Setting.three_sixty_dialog_whats_app_rest_api_endpoint}/messages")
headers = { 'D360-API-KEY' => Setting.three_sixty_dialog_client_api_key, 'Content-Type' => 'application/json' }
request = Net::HTTP::Post.new(url.to_s, headers)

request.body = payload.to_json
response = Net::HTTP.start(url.host, url.port, use_ssl: true) do |http|
http.request(request)
end
handle_response(response)
end

private

def handle_response(response)
case response.code.to_i
when 201
Rails.logger.debug 'Great!'
when 400..599
exception = WhatsAppAdapter::ThreeSixtyDialogError.new(error_code: response.code, message: response.body)
ErrorNotifier.report(exception)
end
end
end
end
end
9 changes: 9 additions & 0 deletions app/adapters/whats_app_adapter/three_sixty_dialog_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module WhatsAppAdapter
class ThreeSixtyDialogError < StandardError
def initialize(error_code:, message:)
super("Error occurred for WhatsApp with error code: #{error_code} with message: #{message}")
end
end
end
Loading

0 comments on commit beee331

Please sign in to comment.