add webhook events
This commit is contained in:
committed by
Pete Matsyburka
parent
1b60b42428
commit
988a5361a6
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module HighlightCode
|
||||
module_function
|
||||
|
||||
def call(code, lexer, theme: 'base16.light')
|
||||
require 'rouge/themes/base16' unless Rouge::Theme.registry[theme]
|
||||
|
||||
formatter = Rouge::Formatters::HTMLInline.new(theme)
|
||||
lexer = Rouge::Lexers.const_get(lexer.to_sym).new
|
||||
formatted_code = formatter.format(lexer.lex(code))
|
||||
formatted_code = formatted_code.gsub('background-color: #181818', '') if theme == 'base16.dark'
|
||||
formatted_code
|
||||
end
|
||||
end
|
||||
@@ -5,12 +5,16 @@ module SendWebhookRequest
|
||||
|
||||
LOCALHOSTS = %w[0.0.0.0 127.0.0.1 localhost].freeze
|
||||
|
||||
MANUAL_ATTEMPT = 99_999
|
||||
AUTOMATED_RETRY_RANGE = 1..MANUAL_ATTEMPT - 1
|
||||
|
||||
HttpsError = Class.new(StandardError)
|
||||
LocalhostError = Class.new(StandardError)
|
||||
|
||||
module_function
|
||||
|
||||
def call(webhook_url, event_type:, data:)
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def call(webhook_url, event_uuid:, event_type:, record:, data:, attempt: 0)
|
||||
uri = begin
|
||||
URI(webhook_url.url)
|
||||
rescue URI::Error
|
||||
@@ -24,21 +28,79 @@ module SendWebhookRequest
|
||||
raise LocalhostError, "Can't send to localhost." if uri.host.in?(LOCALHOSTS)
|
||||
end
|
||||
|
||||
Faraday.post(uri) do |req|
|
||||
webhook_event = create_webhook_event(webhook_url, event_uuid:, event_type:, record:)
|
||||
|
||||
return if AUTOMATED_RETRY_RANGE.cover?(attempt.to_i) && webhook_event&.status == 'success'
|
||||
|
||||
response = Faraday.post(uri) do |req|
|
||||
req.headers['Content-Type'] = 'application/json'
|
||||
req.headers['User-Agent'] = USER_AGENT
|
||||
req.headers.merge!(webhook_url.secret.to_h) if webhook_url.secret.present?
|
||||
|
||||
req.body = {
|
||||
event_type: event_type,
|
||||
timestamp: Time.current,
|
||||
timestamp: webhook_event&.created_at || Time.current,
|
||||
data: data
|
||||
}.to_json
|
||||
|
||||
req.options.read_timeout = 8
|
||||
req.options.open_timeout = 8
|
||||
end
|
||||
rescue Faraday::Error
|
||||
|
||||
handle_response(webhook_event, response:, attempt:)
|
||||
rescue Faraday::SSLError, Faraday::TimeoutError, Faraday::ConnectionFailed => e
|
||||
handle_error(webhook_event, attempt:, error_message: e.class.name.split('::').last)
|
||||
rescue Faraday::Error => e
|
||||
handle_error(webhook_event, attempt:, error_message: e.message&.truncate(100))
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
|
||||
def create_webhook_event(webhook_url, event_uuid:, event_type:, record:)
|
||||
return if event_uuid.blank?
|
||||
|
||||
WebhookEvent.create_with(
|
||||
event_type:,
|
||||
record:,
|
||||
account_id: webhook_url.account_id,
|
||||
status: 'pending'
|
||||
).find_or_create_by!(webhook_url:, uuid: event_uuid)
|
||||
end
|
||||
|
||||
def handle_response(webhook_event, response:, attempt:)
|
||||
return response unless webhook_event
|
||||
|
||||
WebhookAttempt.create!(
|
||||
webhook_event:,
|
||||
response_body: response.body&.truncate(100),
|
||||
response_status_code: response.status,
|
||||
attempt:
|
||||
)
|
||||
|
||||
webhook_event.update!(status: response.success? ? 'success' : 'error')
|
||||
|
||||
response
|
||||
rescue StandardError
|
||||
raise if Rails.env.local?
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def handle_error(webhook_event, error_message:, attempt:)
|
||||
return unless webhook_event
|
||||
|
||||
WebhookAttempt.create!(
|
||||
webhook_event:,
|
||||
response_body: error_message,
|
||||
response_status_code: 0,
|
||||
attempt:
|
||||
)
|
||||
|
||||
webhook_event.update!(status: 'error')
|
||||
|
||||
nil
|
||||
rescue StandardError
|
||||
raise if Rails.env.local?
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,10 +16,7 @@ module Submitters
|
||||
unless submitter.submission_events.exists?(event_type: 'start_form')
|
||||
SubmissionEvents.create_with_tracking_data(submitter, 'start_form', request)
|
||||
|
||||
WebhookUrls.for_account_id(submitter.account_id, 'form.started').each do |webhook_url|
|
||||
SendFormStartedWebhookRequestJob.perform_async('submitter_id' => submitter.id,
|
||||
'webhook_url_id' => webhook_url.id)
|
||||
end
|
||||
WebhookUrls.enqueue_events(submitter, 'form.started')
|
||||
end
|
||||
|
||||
update_submitter!(submitter, params, request, validate_required:)
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module WebhookUrls
|
||||
EVENT_TYPE_TO_JOB_CLASS = {
|
||||
'form.started' => SendFormStartedWebhookRequestJob,
|
||||
'form.completed' => SendFormCompletedWebhookRequestJob,
|
||||
'form.declined' => SendFormDeclinedWebhookRequestJob,
|
||||
'form.viewed' => SendFormViewedWebhookRequestJob,
|
||||
'submission.created' => SendSubmissionCreatedWebhookRequestJob,
|
||||
'submission.completed' => SendSubmissionCompletedWebhookRequestJob,
|
||||
'submission.expired' => SendSubmissionExpiredWebhookRequestJob,
|
||||
'submission.archived' => SendSubmissionArchivedWebhookRequestJob,
|
||||
'template.created' => SendTemplateCreatedWebhookRequestJob,
|
||||
'template.updated' => SendTemplateUpdatedWebhookRequestJob
|
||||
}.freeze
|
||||
|
||||
EVENT_TYPE_ID_KEYS = {
|
||||
'form' => 'submitter_id',
|
||||
'submission' => 'submission_id',
|
||||
'template' => 'template_id'
|
||||
}.freeze
|
||||
|
||||
module_function
|
||||
|
||||
def for_account_id(account_id, events)
|
||||
@@ -24,4 +43,26 @@ module WebhookUrls
|
||||
(account_urls.present? ? WebhookUrl.none : linked_urls)
|
||||
end
|
||||
end
|
||||
|
||||
def enqueue_events(records, event_type)
|
||||
args = []
|
||||
|
||||
id_key = EVENT_TYPE_ID_KEYS.fetch(event_type.split('.').first)
|
||||
|
||||
Array.wrap(records).group_by(&:account_id).each do |account_id, account_records|
|
||||
webhook_urls = for_account_id(account_id, event_type)
|
||||
|
||||
account_records.each do |record|
|
||||
event_uuid = SecureRandom.uuid
|
||||
|
||||
webhook_urls.each do |webhook_url|
|
||||
next unless webhook_url.events.include?(event_type)
|
||||
|
||||
args << [{ id_key => record.id, 'webhook_url_id' => webhook_url.id, 'event_uuid' => event_uuid }]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Sidekiq::Client.push_bulk('class' => EVENT_TYPE_TO_JOB_CLASS[event_type], 'args' => args)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user