Remove Rails Observer dependency

This commit is contained in:
Darren Clarke 2023-07-18 10:02:39 +00:00 committed by GitHub
parent 6e6cc22d2b
commit b5ccd86660
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 304 additions and 329 deletions

View file

@ -59,6 +59,7 @@ services:
# context: .
# dockerfile: ./apps/metamigo-frontend/Dockerfile
# image: registry.gitlab.com/digiresilience/link/link-stack/metamigo-frontend:${LINK_STACK_VERSION}
command: [ "frontend" ]
image: registry.gitlab.com/digiresilience/link/metamigo:develop
container_name: metamigo-frontend
restart: ${RESTART}
@ -78,8 +79,8 @@ services:
# context: .
# dockerfile: ./apps/metamigo-cli/Dockerfile
# image: registry.gitlab.com/digiresilience/link/link-stack/metamigo:${LINK_STACK_VERSION}
# container_name: metamigo-worker
image: registry.gitlab.com/digiresilience/link/metamigo:develop
container_name: metamigo-worker
restart: ${RESTART}
command: [ "worker" ]
environment: *common-metamigo-variables

View file

@ -21,7 +21,6 @@ RUN export PATH=~/.cargo/bin:$PATH && cargo build -p sequoia-openpgp-ffi;
WORKDIR ${ZAMMAD_DIR}
RUN echo "gem 'ruby_openpgp', git: 'https://github.com/throneless-tech/ruby_openpgp', branch: 'signing-and-userids'" >> Gemfile.local
RUN echo "gem 'rails-observers'" >> Gemfile.local
RUN bundle install --without test development mysql
RUN sed -i '/^[[:space:]]*# create install ready file/ i\
echo "about to reinstall..."\n\

View file

@ -9,7 +9,7 @@
"dev:metamigo": "dotenv -- turbo run dev --concurrency 30 --filter=!link --filter=!leafcutter",
"migrate": "dotenv -- npm run migrate --workspace=@digiresilience/metamigo-cli",
"fmt": "turbo run fmt",
"docker:all:up": "docker compose -f docker-compose.zammad.yml -f docker-compose.metamigo-postgresql.yml -f docker-compose.metamigo.yml -f docker-compose.opensearch.yml -f docker-compose.leafcutter.yml -f docker-compose.link.yml up -d",
"docker:all:up": "CURRENT_UID=$(CURRENT_UID) docker compose -f docker-compose.zammad.yml -f docker-compose.metamigo-postgresql.yml -f docker-compose.metamigo.yml -f docker-compose.opensearch.yml -f docker-compose.leafcutter.yml -f docker-compose.link.yml up -d",
"docker:all:down": "docker compose -f docker-compose.zammad.yml -f docker-compose.metamigo-postgresql.yml -f docker-compose.metamigo.yml -f docker-compose.opensearch.yml -f docker-compose.leafcutter.yml -f docker-compose.link.yml down",
"docker:all:build": "docker compose -f docker-compose.zammad.yml -f docker-compose.metamigo-postgresql.yml -f docker-compose.metamigo.yml -f docker-compose.opensearch.yml -f docker-compose.leafcutter.yml -f docker-compose.link.yml up --build -d",
"docker:link:dev:up": "docker compose -f docker-compose.metamigo-postgresql.yml -f docker-compose.metamigo.yml -f docker-compose.zammad.yml up -d",
@ -22,6 +22,9 @@
"docker:leafcutter:up": "docker compose -f docker-compose.opensearch.yml -f docker-compose.leafcutter.yml up -d",
"docker:leafcutter:down": "docker compose -f docker-compose.opensearch.yml -f docker-compose.leafcutter.yml down",
"docker:leafcutter:build": "docker compose -f docker-compose.leafcutter.yml up --build -d",
"docker:zammad:up": "docker compose -f docker-compose.zammad.yml up -d",
"docker:zammad:down": "docker compose -f docker-compose.zammad.yml down",
"docker:zammad:build": "docker compose -f docker-compose.zammad.yml up --build -d",
"docker:metamigo:dev:up": "docker compose -f docker-compose.metamigo-postgresql.yml -f docker-compose.zammad.yml up -d",
"docker:metamigo:dev:down": "docker compose -f docker-compose.metamigo-postgresql.yml -f docker-compose.zammad.yml down",
"docker:metamigo:up": "docker compose -f docker-compose.zammad.yml -f docker-compose.metamigo-postgresql.yml -f docker-compose.metamigo.yml up -d",

View file

@ -0,0 +1,117 @@
# frozen_string_literal: true
class CommunicateCdrSignalJob < ApplicationJob
retry_on StandardError, attempts: 4, wait: lambda { |executions|
executions * 120.seconds
}
def perform(article_id)
article = Ticket::Article.find(article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
unless ticket.preferences
log_error(article,
"Can't find ticket.preferences for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_signal']
log_error(article,
"Can't find ticket.preferences['cdr_signal'] for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_signal']['bot_token']
log_error(article,
"Can't find ticket.preferences['cdr_signal']['bot_token'] for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_signal']['chat_id']
log_error(article,
"Can't find ticket.preferences['cdr_signal']['chat_id'] for Ticket.find(#{article.ticket_id})")
end
channel = ::CdrSignal.bot_by_bot_token(ticket.preferences['cdr_signal']['bot_token'])
channel ||= ::Channel.lookup(id: ticket.preferences['channel_id'])
unless channel
log_error(article,
"No such channel for bot #{ticket.preferences['cdr_signal']['bot_token']} or channel id #{ticket.preferences['channel_id']}")
end
if channel.options[:bot_token].blank?
log_error(article,
"Channel.find(#{channel.id}) has no cdr signal api token!")
end
has_error = false
begin
result = channel.deliver(
to: ticket.preferences[:cdr_signal][:chat_id],
body: article.body
)
rescue StandardError => e
log_error(article, e.message)
has_error = true
end
Rails.logger.debug { "send result: #{result}" }
if result.nil? || result[:error].present?
log_error(article, 'Delivering signal message failed!')
has_error = true
end
return if has_error
article.to = result['result']['recipient']
article.from = result['result']['source']
message_id = format('%<source>s@%<timestamp>s', source: result['result']['source'],
timestamp: result['result']['timestamp'])
article.preferences['cdr_signal'] = {
timestamp: result['result']['timestamp'],
message_id: message_id,
from: result['result']['source'],
to: result['result']['recipient']
}
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.message_id = "cdr_signal.#{message_id}"
article.save!
Rails.logger.info "Sent signal message to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] =
message.encode!('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send cdr signal message: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true
},
updated_by_id: 1,
created_by_id: 1
)
end
raise message
end
end

View file

@ -0,0 +1,117 @@
# frozen_string_literal: true
class CommunicateCdrWhatsappJob < ApplicationJob
retry_on StandardError, attempts: 4, wait: lambda { |executions|
executions * 120.seconds
}
def perform(article_id)
article = Ticket::Article.find(article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = Ticket.lookup(id: article.ticket_id)
unless ticket.preferences
log_error(article,
"Can't find ticket.preferences for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_whatsapp']
log_error(article,
"Can't find ticket.preferences['cdr_whatsapp'] for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_whatsapp']['bot_token']
log_error(article,
"Can't find ticket.preferences['cdr_whatsapp']['bot_token'] for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_whatsapp']['chat_id']
log_error(article,
"Can't find ticket.preferences['cdr_whatsapp']['chat_id'] for Ticket.find(#{article.ticket_id})")
end
channel = ::CdrSignal.bot_by_bot_token(ticket.preferences['cdr_whatsapp']['bot_token'])
channel ||= ::Channel.lookup(id: ticket.preferences['channel_id'])
unless channel
log_error(article,
"No such channel for bot #{ticket.preferences['cdr_whatsapp']['bot_token']} or channel id #{ticket.preferences['channel_id']}")
end
if channel.options[:bot_token].blank?
log_error(article,
"Channel.find(#{channel.id}) has no cdr whatsapp api token!")
end
has_error = false
begin
result = channel.deliver(
to: ticket.preferences[:cdr_whatsapp][:chat_id],
body: article.body
)
rescue StandardError => e
log_error(article, e.message)
has_error = true
end
Rails.logger.debug { "send result: #{result}" }
if result.nil? || result[:error].present?
log_error(article, 'Delivering whatsapp message failed!')
has_error = true
end
return if has_error
article.to = result['result']['recipient']
article.from = result['result']['source']
message_id = format('%<source>s@%<timestamp>s', source: result['result']['source'],
timestamp: result['result']['timestamp'])
article.preferences['cdr_whatsapp'] = {
timestamp: result['result']['timestamp'],
message_id: message_id,
from: result['result']['source'],
to: result['result']['recipient']
}
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.message_id = "cdr_whatsapp.#{message_id}"
article.save!
Rails.logger.info "Sent whatsapp message to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] =
message.encode!('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send cdr whatsapp message: #{message}",
internal: true,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true
},
updated_by_id: 1,
created_by_id: 1
)
end
raise message
end
end

View file

@ -1,25 +0,0 @@
# frozen_string_literal: true
class Observer::Ticket::Article::CommunicateCdrSignal < ActiveRecord::Observer
observe 'ticket::_article'
def after_create(record)
# return if we run import mode
return true if Setting.get('import_mode')
# if sender is customer, do not communicate
return true unless record.sender_id
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
return true if sender.nil?
return true if sender.name == 'Customer'
# only apply on signal messages
return true unless record.type_id
type = Ticket::Article::Type.lookup(id: record.type_id)
return true if type.name !~ /\Acdr_signal/i
Delayed::Job.enqueue(Observer::Ticket::Article::CommunicateCdrSignal::BackgroundJob.new(record.id))
end
end

View file

@ -1,137 +0,0 @@
# frozen_string_literal: true
module Observer
module Ticket
module Article
class CommunicateCdrSignal
class BackgroundJob
def initialize(id)
@article_id = id
end
def perform
article = ::Ticket::Article.find(@article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = ::Ticket.lookup(id: article.ticket_id)
Rails.logger.debug { 'Signal background job' }
Rails.logger.debug { ticket.inspect }
Rails.logger.debug { article.inspect }
unless ticket.preferences
log_error(article,
"Can't find ticket.preferences for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_signal']
log_error(article,
"Can't find ticket.preferences['cdr_signal'] for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_signal']['chat_id']
log_error(article,
"Can't find ticket.preferences['cdr_signal']['chat_id'] for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_signal']['bot_token']
log_error(article,
"Can't find ticket.preferences['cdr_signal']['bot_token'] for Ticket.find(#{article.ticket_id})")
end
channel = ::CdrSignal.bot_by_bot_token(ticket.preferences['cdr_signal']['bot_token'])
Rails.logger.debug { "signal got channel for #{channel.inspect}" }
channel ||= ::Channel.lookup(id: ticket.preferences['channel_id'])
unless channel
log_error(article,
"No such channel for bot #{ticket.preferences['cdr_signal']['bot_token']} or channel id #{ticket.preferences['channel_id']}")
end
if channel.options[:bot_token].blank?
log_error(article,
"Channel.find(#{channel.id}) has no signal api token!")
end
begin
result = channel.deliver(
to: ticket.preferences[:cdr_signal][:chat_id],
body: article.body
)
rescue StandardError => e
log_error(article, e.message)
return
end
Rails.logger.debug { "send result: #{result}" }
if result.nil? || result[:error].present?
log_error(article, 'Delivering signal message failed!')
return
end
article.to = result['result']['recipient']
article.from = result['result']['source']
message_id = format('%<source>s@%<timestamp>s', source: result['result']['source'],
timestamp: result['result']['timestamp'])
article.preferences['cdr_signal'] = {
timestamp: result['result']['timestamp'],
message_id: message_id,
from: result['result']['source'],
to: result['result']['recipient']
}
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.message_id = "cdr_signal.#{message_id}"
article.save!
Rails.logger.info "Sent signal message to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] =
message.encode('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
::Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send signal message: #{message}",
internal: true,
sender: ::Ticket::Article::Sender.find_by(name: 'System'),
type: ::Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true
},
updated_by_id: 1,
created_by_id: 1
)
end
raise message
end
def max_attempts
4
end
def reschedule_at(current_time, attempts)
return current_time + attempts * 120.seconds if Rails.env.production?
current_time + 5.seconds
end
end
end
end
end
end

View file

@ -1,25 +0,0 @@
# frozen_string_literal: true
class Observer::Ticket::Article::CommunicateCdrWhatsapp < ActiveRecord::Observer
observe 'ticket::_article'
def after_create(record)
# return if we run import mode
return true if Setting.get('import_mode')
# if sender is customer, do not communicate
return true unless record.sender_id
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
return true if sender.nil?
return true if sender.name == 'Customer'
# only apply on whatsapp messages
return true unless record.type_id
type = Ticket::Article::Type.lookup(id: record.type_id)
return true if type.name !~ /\Acdr_whatsapp/i
Delayed::Job.enqueue(Observer::Ticket::Article::CommunicateCdrWhatsapp::BackgroundJob.new(record.id))
end
end

View file

@ -1,137 +0,0 @@
# frozen_string_literal: true
module Observer
module Ticket
module Article
class CommunicateCdrWhatsapp
class BackgroundJob
def initialize(id)
@article_id = id
end
def perform
article = ::Ticket::Article.find(@article_id)
# set retry count
article.preferences['delivery_retry'] ||= 0
article.preferences['delivery_retry'] += 1
ticket = ::Ticket.lookup(id: article.ticket_id)
Rails.logger.debug { 'Whatsapp background job' }
Rails.logger.debug { ticket.inspect }
Rails.logger.debug { article.inspect }
unless ticket.preferences
log_error(article,
"Can't find ticket.preferences for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_whatsapp']
log_error(article,
"Can't find ticket.preferences['cdr_whatsapp'] for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_whatsapp']['chat_id']
log_error(article,
"Can't find ticket.preferences['cdr_whatsapp']['chat_id'] for Ticket.find(#{article.ticket_id})")
end
unless ticket.preferences['cdr_whatsapp']['bot_token']
log_error(article,
"Can't find ticket.preferences['cdr_whatsapp']['bot_token'] for Ticket.find(#{article.ticket_id})")
end
channel = ::CdrWhatsapp.bot_by_bot_token(ticket.preferences['cdr_whatsapp']['bot_token'])
Rails.logger.debug { "whatsapp got channel for #{channel.inspect}" }
channel ||= ::Channel.lookup(id: ticket.preferences['channel_id'])
unless channel
log_error(article,
"No such channel for bot #{ticket.preferences['cdr_whatsapp']['bot_token']} or channel id #{ticket.preferences['channel_id']}")
end
if channel.options[:bot_token].blank?
log_error(article,
"Channel.find(#{channel.id}) has no whatsapp api token!")
end
begin
result = channel.deliver(
to: ticket.preferences[:cdr_whatsapp][:chat_id],
body: article.body
)
rescue StandardError => e
log_error(article, e.message)
return
end
Rails.logger.debug { "send result: #{result}" }
if result.nil? || result[:error].present?
log_error(article, 'Delivering whatsapp message failed!')
return
end
article.to = result['result']['recipient']
article.from = result['result']['source']
message_id = format('%<source>s@%<timestamp>s', source: result['result']['source'],
timestamp: result['result']['timestamp'])
article.preferences['cdr_whatsapp'] = {
timestamp: result['result']['timestamp'],
message_id: message_id,
from: result['result']['source'],
to: result['result']['recipient']
}
# set delivery status
article.preferences['delivery_status_message'] = nil
article.preferences['delivery_status'] = 'success'
article.preferences['delivery_status_date'] = Time.zone.now
article.message_id = "cdr_whatsapp.#{message_id}"
article.save!
Rails.logger.info "Sent whatsapp message to: '#{article.to}' (from #{article.from})"
article
end
def log_error(local_record, message)
local_record.preferences['delivery_status'] = 'fail'
local_record.preferences['delivery_status_message'] =
message.encode('UTF-8', 'UTF-8', invalid: :replace, replace: '?')
local_record.preferences['delivery_status_date'] = Time.zone.now
local_record.save
Rails.logger.error message
if local_record.preferences['delivery_retry'] > 3
::Ticket::Article.create(
ticket_id: local_record.ticket_id,
content_type: 'text/plain',
body: "Unable to send whatsapp message: #{message}",
internal: true,
sender: ::Ticket::Article::Sender.find_by(name: 'System'),
type: ::Ticket::Article::Type.find_by(name: 'note'),
preferences: {
delivery_article_id_related: local_record.id,
delivery_message: true
},
updated_by_id: 1,
created_by_id: 1
)
end
raise message
end
def max_attempts
4
end
def reschedule_at(current_time, attempts)
return current_time + attempts * 120.seconds if Rails.env.production?
current_time + 5.seconds
end
end
end
end
end
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
module Ticket::Article::EnqueueCommunicateCdrSignalJob
extend ActiveSupport::Concern
included do
after_create :ticket_article_enqueue_communicate_cdr_signal_job
end
private
def ticket_article_enqueue_communicate_cdr_signal_job
# return if we run import mode
return true if Setting.get('import_mode')
# if sender is customer, do not communicate
return true unless sender_id
sender = Ticket::Article::Sender.lookup(id: sender_id)
return true if sender.nil?
return true if sender.name == 'Customer'
# only apply on cdr signal messages
return true unless type_id
type = Ticket::Article::Type.lookup(id: type_id)
return true unless type.name.match?(/\Acdr_signal/i)
CommunicateCdrSignalJob.perform_later(id)
end
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
module Ticket::Article::EnqueueCommunicateCdrWhatsappJob
extend ActiveSupport::Concern
included do
after_create :ticket_article_enqueue_communicate_cdr_whatsapp_job
end
private
def ticket_article_enqueue_communicate_cdr_whatsapp_job
# return if we run import mode
return true if Setting.get('import_mode')
# if sender is customer, do not communicate
return true unless sender_id
sender = Ticket::Article::Sender.lookup(id: sender_id)
return true if sender.nil?
return true if sender.name == 'Customer'
# only apply on cdr whatsapp messages
return true unless type_id
type = Ticket::Article::Type.lookup(id: type_id)
return true unless type.name.match?(/\Acdr_whatspp/i)
CommunicateCdrWhatsappJob.perform_later(id)
end
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Rails.application.config.after_initialize do
Ticket::Article.add_observer Observer::Ticket::Article::CommunicateCdrSignal.instance
# Ticket::Article.add_observer Observer::Ticket::Article::CommunicateCdrSignal.instance
icon = File.read('public/assets/images/icons/cdr_signal.svg')
doc = File.open('public/assets/images/icons.svg') { |f| Nokogiri::XML(f) }

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Rails.application.config.after_initialize do
Ticket::Article.add_observer Observer::Ticket::Article::CommunicateCdrWhatsapp.instance
# Ticket::Article.add_observer Observer::Ticket::Article::CommunicateCdrWhatsapp.instance
icon = File.read('public/assets/images/icons/cdr_whatsapp.svg')
doc = File.open('public/assets/images/icons.svg') { |f| Nokogiri::XML(f) }