Skip to content

Commit 19abefb

Browse files
committed
add template.preferences_updated webhook job
1 parent 882d7dd commit 19abefb

3 files changed

Lines changed: 160 additions & 1 deletion

app/jobs/process_submitter_completion_job.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def perform(params = {})
2424

2525
create_completed_documents!(submitter)
2626

27-
if !is_all_completed && submitter.submission.submitters_order_preserved? && params['send_invitation_email'] != false
27+
if !is_all_completed && submitter.submission.signing_order_enforced? && params['send_invitation_email'] != false
2828
enqueue_next_submitter_request_notification(submitter)
2929
end
3030

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
class SendTemplatePreferencesUpdatedWebhookRequestJob
4+
include Sidekiq::Job
5+
6+
sidekiq_options queue: :webhooks
7+
8+
def perform(params = {})
9+
template = Template.find(params['template_id'])
10+
webhook_url = WebhookUrl.find(params['webhook_url_id'])
11+
12+
attempt = params['attempt'].to_i
13+
14+
return if webhook_url.url.blank? || webhook_url.events.exclude?('template.preferences_updated')
15+
16+
data = {
17+
id: template.id,
18+
external_id: template.external_id,
19+
application_key: template.application_key,
20+
submitters_order: template.preferences['submitters_order']
21+
}
22+
23+
resp = SendWebhookRequest.call(webhook_url, event_type: 'template.preferences_updated', data:)
24+
25+
return unless WebhookRetryLogic.should_retry?(response: resp, attempt: attempt, record: template)
26+
27+
SendTemplatePreferencesUpdatedWebhookRequestJob.perform_in((2**attempt).minutes, {
28+
'template_id' => template.id,
29+
'webhook_url_id' => webhook_url.id,
30+
'attempt' => attempt + 1,
31+
'last_status' => resp&.status.to_i
32+
})
33+
end
34+
end
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe SendTemplatePreferencesUpdatedWebhookRequestJob do
4+
let(:account) { create(:account) }
5+
let(:user) { create(:user, account:) }
6+
let(:template) { create(:template, account:, author: user) }
7+
let(:webhook_url) { create(:webhook_url, account:, events: ['template.preferences_updated']) }
8+
9+
before do
10+
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
11+
value: GenerateCertificate.call.transform_values(&:to_pem))
12+
end
13+
14+
describe '#perform' do
15+
before do
16+
stub_request(:post, webhook_url.url).to_return(status: 200)
17+
end
18+
19+
it 'sends a webhook request with minimal submitters_order data' do
20+
template.update!(preferences: { 'submitters_order' => 'employee_then_manager' })
21+
22+
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
23+
24+
expect(WebMock).to have_requested(:post, webhook_url.url).with(
25+
body: {
26+
'event_type' => 'template.preferences_updated',
27+
'timestamp' => /.*/,
28+
'data' => {
29+
'id' => template.id,
30+
'external_id' => template.external_id,
31+
'application_key' => template.application_key,
32+
'submitters_order' => 'employee_then_manager'
33+
}
34+
},
35+
headers: {
36+
'Content-Type' => 'application/json',
37+
'User-Agent' => 'DocuSeal.com Webhook'
38+
}
39+
).once
40+
end
41+
42+
it 'sends a webhook request with the secret' do
43+
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
44+
template.update!(preferences: { 'submitters_order' => 'simultaneous' })
45+
46+
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
47+
48+
expect(WebMock).to have_requested(:post, webhook_url.url).with(
49+
body: {
50+
'event_type' => 'template.preferences_updated',
51+
'timestamp' => /.*/,
52+
'data' => {
53+
'id' => template.id,
54+
'external_id' => template.external_id,
55+
'application_key' => template.application_key,
56+
'submitters_order' => 'simultaneous'
57+
}
58+
},
59+
headers: {
60+
'Content-Type' => 'application/json',
61+
'User-Agent' => 'DocuSeal.com Webhook',
62+
'X-Secret-Header' => 'secret_value'
63+
}
64+
).once
65+
end
66+
67+
it "doesn't send a webhook request if the event is not in the webhook's events" do
68+
webhook_url.update!(events: ['template.created'])
69+
70+
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
71+
72+
expect(WebMock).not_to have_requested(:post, webhook_url.url)
73+
end
74+
75+
it 'sends again if the response status is 400 or higher' do
76+
stub_request(:post, webhook_url.url).to_return(status: 401)
77+
78+
expect do
79+
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
80+
end.to change(described_class.jobs, :size).by(1)
81+
82+
expect(WebMock).to have_requested(:post, webhook_url.url).once
83+
84+
args = described_class.jobs.last['args'].first
85+
86+
expect(args['attempt']).to eq(1)
87+
expect(args['last_status']).to eq(401)
88+
expect(args['webhook_url_id']).to eq(webhook_url.id)
89+
expect(args['template_id']).to eq(template.id)
90+
end
91+
92+
it "doesn't send again if the max attempts is reached" do
93+
stub_request(:post, webhook_url.url).to_return(status: 401)
94+
95+
expect do
96+
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id, 'attempt' => 11)
97+
end.not_to change(described_class.jobs, :size)
98+
99+
expect(WebMock).to have_requested(:post, webhook_url.url).once
100+
end
101+
102+
it 'sends webhook with single_sided submitters_order' do
103+
template.update!(preferences: { 'submitters_order' => 'single_sided' })
104+
105+
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
106+
107+
expect(WebMock).to have_requested(:post, webhook_url.url).with(
108+
body: {
109+
'event_type' => 'template.preferences_updated',
110+
'timestamp' => /.*/,
111+
'data' => {
112+
'id' => template.id,
113+
'external_id' => template.external_id,
114+
'application_key' => template.application_key,
115+
'submitters_order' => 'single_sided'
116+
}
117+
},
118+
headers: {
119+
'Content-Type' => 'application/json',
120+
'User-Agent' => 'DocuSeal.com Webhook'
121+
}
122+
).once
123+
end
124+
end
125+
end

0 commit comments

Comments
 (0)