Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0f7f9eb
Initial exploration with claude
Oct 21, 2025
55bf73d
Improved implementation plan
Oct 22, 2025
030a797
Improved implementation plan and added a claude prompt log
Oct 22, 2025
13c522d
WIP webhooks, failing specs
Oct 28, 2025
e846e1d
Fixed delivery_job and specs
Oct 28, 2025
8ada041
More spec fixes
Oct 28, 2025
fd5c79c
Fixed integration spec
Oct 28, 2025
569f274
Clean up subscription on project deletion
Oct 28, 2025
66ca2d7
use delivery instead of delivery_id as tje job argument
Oct 28, 2025
98a8c23
Replay instead of test, shallow routes
Oct 29, 2025
725900a
Use public api serializers, fix specs and linter
Oct 29, 2025
dfa85b7
test delivery replay
Oct 29, 2025
ca00693
Return unmasked secret token on creation and regeneration
Oct 31, 2025
1ab7a58
WIP webhooks front-end, claude generated with significant editing
Oct 31, 2025
fb2a72f
Translations updated by CI (extract-intl)
Oct 31, 2025
d85cfee
Fixed linters
Oct 31, 2025
0bdf3aa
Merge branch 'TAN-5687-webhooks' of github.com:citizenlabdotco/citize…
Oct 31, 2025
3f0ac42
Reorganized table
Nov 1, 2025
ec1e720
Updated structure.sql
Nov 1, 2025
8185e80
Merge branch 'master' into TAN-5687-webhooks
Nov 1, 2025
5693ecb
Fix failing specs through limited scope of Resolv mock
Nov 2, 2025
230b540
Fix lint issues
Nov 2, 2025
6f730e1
Align all webhook subscription urls in specs for sake of mocking
Nov 2, 2025
2bb010c
rubocop
Nov 2, 2025
4a67c22
Cover webhooks under public API feature flag
Nov 2, 2025
b50ca91
Got rid of global Resolv mock
Nov 3, 2025
1d1a2aa
Merge branch 'master' into TAN-5687-webhooks
Nov 3, 2025
85a5ec6
Don't require an initiating user for the idea assignment notification
Nov 3, 2025
509579a
Fix retry bug and add a few more events
Nov 4, 2025
438f84d
Added internal comments to the public API
Nov 5, 2025
2b2f144
Support user.changed event in webhooks
Nov 5, 2025
9717d55
Merge pull request #12428 from CitizenLabDotCo/TAN-5772-n8n-flows
kogre Nov 6, 2025
0934f9c
Addressed review comments and small ui improvements
Nov 6, 2025
a81c852
Fixed lint issue
Nov 6, 2025
bfc46ee
Merge branch 'master' into TAN-5687-webhooks
Nov 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions back/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ commercial_engines = [
'report_builder',
'smart_groups',
'user_custom_fields',
'webhooks',

# ID verification & SSO engines.
'id_auth0',
Expand Down
8 changes: 8 additions & 0 deletions back/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,13 @@ PATH
rails (~> 7.2)
ros-apartment (>= 2.9.0)

PATH
remote: engines/commercial/webhooks
specs:
webhooks (1.0.0)
http
rails (~> 7.0)

PATH
remote: engines/free/document_annotation
specs:
Expand Down Expand Up @@ -1508,6 +1515,7 @@ DEPENDENCIES
user_custom_fields!
vcr (~> 6.2)
volunteering!
webhooks!
webmock (~> 3.23)

RUBY VERSION
Expand Down
9 changes: 9 additions & 0 deletions back/app/jobs/log_activity_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def run(item, action, user, acted_at = nil, options = {})
activity = create_activity(item, action, user, acted_at, options)
trigger_notifications(activity)
trigger_campaigns(activity)
trigger_webhooks(activity)
publish_activity_to_rabbit(activity)
trigger_track_activity_job(activity, item)
end
Expand Down Expand Up @@ -78,6 +79,14 @@ def trigger_campaigns(activity)
EmailCampaigns::TriggerOnActivityJob.perform_later(activity)
end

def trigger_webhooks(activity)
# Optimization: Skip if no webhooks are enabled. This avoids overhead for
# the common case where no webhooks are configured
return unless Webhooks::Subscription.any_enabled?

Webhooks::EnqueueService.new.call(activity)
end

def publish_activity_to_rabbit(activity)
PublishActivityToRabbitJob.perform_later(activity)
end
Expand Down
1 change: 1 addition & 0 deletions back/app/models/custom_field_bin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#
# fk_rails_... (custom_field_id => custom_fields.id)
# fk_rails_... (custom_field_option_id => custom_field_options.id)
#

# A CustomFieldBin defines a subdivision, often relevant for
# statistical/graphing purposes, over the answer-values of a CustomField. This
Expand Down
1 change: 1 addition & 0 deletions back/app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,4 @@ def old_folder_moderators
Project.include(Analysis::Patches::Project)
Project.include(EmailCampaigns::Extensions::Project)
Project.include(BulkImportIdeas::Patches::Project)
Project.include(Webhooks::Patches::Project)
1 change: 1 addition & 0 deletions back/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
mount Seo::Engine => '', as: 'seo'
mount Surveys::Engine => '', as: 'surveys'
mount Volunteering::Engine => '', as: 'volunteering'
mount Webhooks::Engine => '', as: 'webhooks'

namespace :web_api, defaults: { format: :json } do
namespace :v1 do
Expand Down
4 changes: 2 additions & 2 deletions back/config/schemas/settings.schema.json.erb
Original file line number Diff line number Diff line change
Expand Up @@ -1121,8 +1121,8 @@

"public_api_tokens": {
"type": "object",
"title": "Public API tokens",
"description": "Enables the ability to create API tokens for the public API.",
"title": "Public API & Webhooks",
"description": "Enables the ability to create API tokens for the public API and webhooks. This allows external systems to interact with the platform programmatically.",
"additionalProperties": false,
"required": ["allowed", "enabled"],
"properties": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

# This migration comes from webhooks (originally 20251022000001)
class CreateWebhooksSubscriptions < ActiveRecord::Migration[7.1]
def change
create_table :webhooks_subscriptions, id: :uuid do |t|
t.string :name, null: false
t.string :url, null: false
t.string :secret_token, null: false
t.jsonb :events, default: [], null: false
t.uuid :project_id
t.boolean :enabled, default: true, null: false
t.timestamps

t.index :enabled
t.index :project_id
t.index :events, using: :gin
end

add_foreign_key :webhooks_subscriptions, :projects, on_delete: :cascade, validate: false
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

# This migration comes from webhooks (originally 20251022000002)
class CreateWebhooksDeliveries < ActiveRecord::Migration[7.1]
def change
create_table :webhooks_deliveries, id: :uuid do |t|
t.uuid :webhooks_subscription_id, null: false
t.uuid :activity_id, null: false
t.string :event_type, null: false
t.string :status, null: false, default: 'pending'
t.integer :attempts, default: 0, null: false
t.integer :response_code
t.text :response_body
t.text :error_message
t.datetime :last_attempt_at
t.datetime :succeeded_at
t.timestamps

t.index :webhooks_subscription_id
t.index :activity_id
t.index %i[webhooks_subscription_id status]
t.index :created_at
t.index %i[status created_at]
end

add_foreign_key :webhooks_deliveries, :webhooks_subscriptions, on_delete: :cascade, validate: false
add_foreign_key :webhooks_deliveries, :activities, on_delete: :cascade, validate: false
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

# This migration comes from webhooks (originally 20251022000003)
class ValidateWebhooksForeignKeys < ActiveRecord::Migration[7.1]
def change
validate_foreign_key :webhooks_subscriptions, :projects
validate_foreign_key :webhooks_deliveries, :webhooks_subscriptions
validate_foreign_key :webhooks_deliveries, :activities
end
end
Loading