Skip to content

Commit f21c8d3

Browse files
committed
add template.preferences_updated webhook support
- add template.preferences_updated to account default webhook events - guard account create_careerplug_webhook against missing CAREERPLUG_WEBHOOK_URL env var - create partnership-scoped webhook for template.preferences_updated on partnership creation - add template.preferences_updated to WebhookUrl::EVENTS - update PARTNERSHIP_EVENTS to only include template.preferences_updated - return WebhookUrl.none instead of raising for templates with neither account nor partnership - extend webhooks:setup_development rake task to create partnership webhooks
1 parent 19abefb commit f21c8d3

10 files changed

Lines changed: 110 additions & 83 deletions

app/models/account.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ def default_template_folder
7878
private
7979

8080
def create_careerplug_webhook
81-
return if ENV['CAREERPLUG_WEBHOOK_SECRET'].blank?
81+
return if ENV['CAREERPLUG_WEBHOOK_SECRET'].blank? || ENV['CAREERPLUG_WEBHOOK_URL'].blank?
8282

8383
webhook_urls.create!(
8484
url: ENV.fetch('CAREERPLUG_WEBHOOK_URL'),
85-
events: %w[form.viewed form.started form.completed form.declined],
85+
events: %w[form.viewed form.started form.completed form.declined template.preferences_updated],
8686
secret: { 'X-CareerPlug-Secret' => ENV.fetch('CAREERPLUG_WEBHOOK_SECRET') }
8787
)
8888
end

app/models/partnership.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class Partnership < ApplicationRecord
2222
validates :external_partnership_id, presence: true, uniqueness: true
2323
validates :name, presence: true
2424

25+
after_commit :create_careerplug_webhook, on: :create
26+
2527
def self.find_or_create_by_external_id(external_id, name, attributes = {})
2628
find_by(external_partnership_id: external_id) ||
2729
create!(attributes.merge(external_partnership_id: external_id, name: name))
@@ -34,4 +36,14 @@ def default_template_folder(author)
3436
template_folders.create!(name: TemplateFolder::DEFAULT_NAME,
3537
author: author)
3638
end
39+
40+
def create_careerplug_webhook
41+
return if ENV['CAREERPLUG_WEBHOOK_SECRET'].blank? || ENV['CAREERPLUG_WEBHOOK_URL'].blank?
42+
43+
webhook_urls.create!(
44+
url: ENV.fetch('CAREERPLUG_WEBHOOK_URL'),
45+
events: %w[template.preferences_updated],
46+
secret: { 'X-CareerPlug-Secret' => ENV.fetch('CAREERPLUG_WEBHOOK_SECRET') }
47+
)
48+
end
3749
end

app/models/webhook_url.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ class WebhookUrl < ApplicationRecord
3838
submission.archived
3939
template.created
4040
template.updated
41+
template.preferences_updated
4142
].freeze
4243

4344
# Partnership webhooks can only use template events since partnerships don't have submissions/submitters
4445
PARTNERSHIP_EVENTS = %w[
45-
template.created
46-
template.updated
46+
template.preferences_updated
4747
].freeze
4848

4949
belongs_to :account, optional: true

lib/params/submission_create_validator.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
module Params
44
class SubmissionCreateValidator < BaseValidator
55
def call
6-
binding.pry
76
if params[:submission].blank? && (params[:emails].present? || params[:email].present?)
87
validate_creation_from_emails(params)
98
elsif params.key?(:submitters)

lib/tasks/webhooks.rake

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,49 @@ namespace :webhooks do
2626
end
2727
end
2828

29-
desc 'Set up development webhook URLs for all accounts (creates URLs + configures secret)'
29+
desc 'Set up development webhook URLs for all accounts and partnerships (creates URLs + configures secret)'
3030
task setup_development: :environment do
3131
abort 'This task is only for development' unless Rails.env.development?
3232

3333
url = 'http://localhost:3000/api/docuseal/events'
3434
secret = { 'X-CareerPlug-Secret' => 'development_webhook_secret' }
35-
events = %w[form.viewed form.started form.completed form.declined]
35+
sha1 = Digest::SHA1.hexdigest(url)
36+
account_events = %w[form.viewed form.started form.completed form.declined template.preferences_updated]
37+
partnership_events = %w[template.preferences_updated]
3638

3739
created = 0
3840
updated = 0
3941

4042
Account.find_each do |account|
41-
webhook_url = WebhookUrl.find_or_initialize_by(account: account, sha1: Digest::SHA1.hexdigest(url))
43+
webhook_url = WebhookUrl.find_or_initialize_by(account:, sha1:)
4244

4345
if webhook_url.new_record?
44-
webhook_url.assign_attributes(url: url, events: events, secret: secret)
46+
webhook_url.assign_attributes(url:, events: account_events, secret:)
4547
webhook_url.save!
4648
created += 1
4749
puts "Created webhook URL for account #{account.id}: #{account.name}"
4850
elsif webhook_url.secret != secret
49-
webhook_url.update!(secret: secret)
51+
webhook_url.update!(secret:)
5052
updated += 1
5153
puts "Updated webhook secret for account #{account.id}: #{account.name}"
5254
end
5355
end
5456

57+
Partnership.find_each do |partnership|
58+
webhook_url = WebhookUrl.find_or_initialize_by(partnership:, sha1:)
59+
60+
if webhook_url.new_record?
61+
webhook_url.assign_attributes(url:, events: partnership_events, secret:)
62+
webhook_url.save!
63+
created += 1
64+
puts "Created webhook URL for partnership #{partnership.id}: #{partnership.name}"
65+
elsif webhook_url.secret != secret
66+
webhook_url.update!(secret:)
67+
updated += 1
68+
puts "Updated webhook secret for partnership #{partnership.id}: #{partnership.name}"
69+
end
70+
end
71+
5572
puts "Done: #{created} created, #{updated} updated"
5673
end
5774
end

lib/webhook_urls.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ module WebhookUrls
44
module_function
55

66
def for_template(template, events)
7+
return WebhookUrl.none if template.partnership_id.blank? && template.account_id.blank?
8+
79
if template.partnership_id.present?
810
for_partnership_id(template.partnership_id, events)
9-
elsif template.account_id.present?
10-
for_account_id(template.account_id, events)
1111
else
12-
raise ArgumentError, 'Template must have either account_id or partnership_id'
12+
for_account_id(template.account_id, events)
1313
end
1414
end
1515

spec/lib/webhook_urls_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@
6565
end
6666

6767
context 'with a template that has neither account nor partnership' do
68-
let(:template) { build(:template, account: nil, partnership: nil, author: user) }
68+
let(:template) { build(:template, account_id: nil, partnership_id: nil, author: user) }
6969

70-
it 'raises an ArgumentError' do
71-
expect do
72-
described_class.for_template(template, 'template.created')
73-
end.to raise_error(ArgumentError, 'Template must have either account_id or partnership_id')
70+
it 'returns empty relation' do
71+
webhooks = described_class.for_template(template, 'template.created')
72+
expect(webhooks).to eq(WebhookUrl.none)
73+
expect(webhooks.to_a).to be_empty
7474
end
7575
end
7676
end

spec/models/account_create_careerplug_webhook_spec.rb

Lines changed: 0 additions & 65 deletions
This file was deleted.

spec/models/account_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,41 @@
6363
end
6464
end
6565

66+
describe '#create_careerplug_webhook' do
67+
context 'when both env vars are present' do
68+
before do
69+
stub_const('ENV', ENV.to_h.merge(
70+
'CAREERPLUG_WEBHOOK_URL' => 'https://example.com/webhook',
71+
'CAREERPLUG_WEBHOOK_SECRET' => 'secret'
72+
))
73+
end
74+
75+
it 'creates a webhook with the correct events on account creation' do
76+
account = create(:account)
77+
webhook = account.webhook_urls.last
78+
79+
expect(webhook).to be_present
80+
expect(webhook.events).to match_array(%w[
81+
form.viewed
82+
form.started
83+
form.completed
84+
form.declined
85+
template.preferences_updated
86+
])
87+
end
88+
end
89+
90+
context 'when env vars are missing' do
91+
before do
92+
stub_const('ENV', ENV.to_h.except('CAREERPLUG_WEBHOOK_URL', 'CAREERPLUG_WEBHOOK_SECRET'))
93+
end
94+
95+
it 'does not create a webhook' do
96+
expect { create(:account) }.not_to change(WebhookUrl, :count)
97+
end
98+
end
99+
end
100+
66101
describe '#default_template_folder' do
67102
it 'creates default folder when none exists' do
68103
account = create(:account)

spec/models/partnership_spec.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,35 @@
1515
# index_partnerships_on_external_partnership_id (external_partnership_id) UNIQUE
1616
#
1717
describe Partnership do
18+
describe '#create_careerplug_webhook' do
19+
context 'when both env vars are present' do
20+
before do
21+
stub_const('ENV', ENV.to_h.merge(
22+
'CAREERPLUG_WEBHOOK_URL' => 'https://example.com/webhook',
23+
'CAREERPLUG_WEBHOOK_SECRET' => 'secret'
24+
))
25+
end
26+
27+
it 'creates a webhook with the correct events on partnership creation' do
28+
partnership = create(:partnership)
29+
webhook = partnership.webhook_urls.last
30+
31+
expect(webhook).to be_present
32+
expect(webhook.events).to match_array(%w[template.preferences_updated])
33+
end
34+
end
35+
36+
context 'when env vars are missing' do
37+
before do
38+
stub_const('ENV', ENV.to_h.except('CAREERPLUG_WEBHOOK_URL', 'CAREERPLUG_WEBHOOK_SECRET'))
39+
end
40+
41+
it 'does not create a webhook' do
42+
expect { create(:partnership) }.not_to change(WebhookUrl, :count)
43+
end
44+
end
45+
end
46+
1847
describe 'validations' do
1948
it 'validates presence of external_partnership_id' do
2049
partnership = build(:partnership, external_partnership_id: nil)

0 commit comments

Comments
 (0)