mirror of https://github.com/docusealco/docuseal
parent
8929adbe83
commit
e4bb5466f5
@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class WebhookSettingsController < ApplicationController
|
||||||
|
def show
|
||||||
|
@encrypted_config =
|
||||||
|
current_account.encrypted_configs.find_or_initialize_by(key: EncryptedConfig::WEBHOOK_URL_KEY)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@encrypted_config =
|
||||||
|
current_account.encrypted_configs.find_or_initialize_by(key: EncryptedConfig::WEBHOOK_URL_KEY)
|
||||||
|
|
||||||
|
@encrypted_config.update!(encrypted_config_params)
|
||||||
|
|
||||||
|
redirect_back(fallback_location: settings_webhooks_path, notice: 'Webhook URL has been saved.')
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
submitter = current_account.submitters.where.not(completed_at: nil).order(:id).last
|
||||||
|
|
||||||
|
SendWebhookRequestJob.perform_later(submitter)
|
||||||
|
|
||||||
|
redirect_back(fallback_location: settings_webhooks_path, notice: 'Webhook request has been sent.')
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def encrypted_config_params
|
||||||
|
params.require(:encrypted_config).permit(:value)
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SendWebhookRequestJob < ApplicationJob
|
||||||
|
USER_AGENT = 'DocuSeal.co Webhook'
|
||||||
|
|
||||||
|
def perform(submitter)
|
||||||
|
config = submitter.submission.account.encrypted_configs.find_by(key: EncryptedConfig::WEBHOOK_URL_KEY)
|
||||||
|
|
||||||
|
return if config.blank? || config.value.blank?
|
||||||
|
|
||||||
|
Submissions::EnsureResultGenerated.call(submitter)
|
||||||
|
|
||||||
|
ActiveStorage::Current.url_options = Docuseal.default_url_options
|
||||||
|
|
||||||
|
Faraday.post(config.value,
|
||||||
|
{
|
||||||
|
event_type: 'form.submitted',
|
||||||
|
timestamp: Time.current.iso8601,
|
||||||
|
data: Submitters::SerializeForWebhook.call(submitter)
|
||||||
|
}.to_json,
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'User-Agent' => USER_AGENT)
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
<div class="flex flex-wrap space-y-4 md:flex-nowrap md:space-y-0 md:space-x-10">
|
||||||
|
<%= render 'shared/settings_nav' %>
|
||||||
|
<div class="flex-grow">
|
||||||
|
<h1 class="text-4xl font-bold mb-4">Webhooks</h1>
|
||||||
|
<div class="card bg-base-200">
|
||||||
|
<div class="card-body p-6">
|
||||||
|
<%= form_for @encrypted_config, url: settings_webhooks_path, method: :post, html: { autocomplete: 'off' } do |f| %>
|
||||||
|
<%= f.label :value, 'Webhook URL', class: 'text-sm font-semibold' %>
|
||||||
|
<div class="flex flex-row space-x-4 mt-2">
|
||||||
|
<%= f.text_field :value, required: true, class: 'input font-mono input-bordered w-full', placeholder: 'https://example.com/hook' %>
|
||||||
|
<%= f.button button_title(title: 'Save', disabled_with: 'Saving'), class: 'base-button w-32' %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% submitter = current_account.submitters.where.not(completed_at: nil).order(:id).last %>
|
||||||
|
<% if submitter %>
|
||||||
|
<div class="space-y-4 mt-4">
|
||||||
|
<div class="collapse collapse-open bg-base-200 px-1">
|
||||||
|
<div class="p-4 text-xl font-medium">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>
|
||||||
|
Submission example payload
|
||||||
|
</span>
|
||||||
|
<% if @encrypted_config.value.present? %>
|
||||||
|
<%= button_to button_title(title: 'Test Webhook', disabled_with: 'Sending', icon_disabled: svg_icon('loader', class: 'w-4 h-4 animate-spin')), settings_webhooks_path, class: 'btn btn-neutral btn-outline btn-sm', method: :put %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="collapse-content" style="display: inherit">
|
||||||
|
<div class="mockup-code overflow-hidden relative">
|
||||||
|
<span class="top-0 right-0 absolute">
|
||||||
|
<%= render 'shared/clipboard_copy', icon: 'copy', text: code = JSON.pretty_generate({ event_type: 'form.submitted', timestamp: Time.current.iso8601, data: Submitters::SerializeForWebhook.call(submitter) }).gsub(/^/, ' ').sub(/^\s+/, ''), class: 'btn btn-ghost text-white', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy', copied_title: 'Copied' %>
|
||||||
|
</span>
|
||||||
|
<pre><code class="overflow-hidden w-full"><%= code %></code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Submitters
|
||||||
|
module SerializeForWebhook
|
||||||
|
module_function
|
||||||
|
|
||||||
|
def call(submitter)
|
||||||
|
values = build_values_array(submitter)
|
||||||
|
documents = build_documents_array(submitter)
|
||||||
|
|
||||||
|
submitter_name = submitter.submission.template_submitters.find { |e| e['uuid'] == submitter.uuid }['name']
|
||||||
|
|
||||||
|
submitter.as_json(include: [template: { only: %i[id name created_at updated_at] }])
|
||||||
|
.except('uuid', 'values', 'slug')
|
||||||
|
.merge('values' => values,
|
||||||
|
'documents' => documents,
|
||||||
|
'submitter_name' => submitter_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_values_array(submitter)
|
||||||
|
fields_index = submitter.submission.template_fields.index_by { |e| e['uuid'] }
|
||||||
|
attachments_index = submitter.attachments.preload(:blob).index_by(&:uuid)
|
||||||
|
submitter_field_counters = Hash.new { 0 }
|
||||||
|
|
||||||
|
submitter.values.map do |uuid, value|
|
||||||
|
field = fields_index[uuid]
|
||||||
|
submitter_field_counters[field['type']] += 1
|
||||||
|
|
||||||
|
field_name =
|
||||||
|
field['name'].presence || "#{field['type'].titleize} Field #{submitter_field_counters[field['type']]}"
|
||||||
|
|
||||||
|
value = fetch_field_value(field, value, attachments_index)
|
||||||
|
|
||||||
|
{ field: field_name, value: }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_documents_array(submitter)
|
||||||
|
submitter.documents.preload(:blob).map do |attachment|
|
||||||
|
{ name: attachment.filename.base, url: attachment.url }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_field_value(field, value, attachments_index)
|
||||||
|
if field['type'].in?(%w[image signature])
|
||||||
|
attachments_index[value]&.url
|
||||||
|
elsif field['type'] == 'file'
|
||||||
|
Array.wrap(value).compact_blank.filter_map { |e| attachments_index[e]&.url }
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in new issue