diff --git a/app/models/nonprofit.rb b/app/models/nonprofit.rb index f2aca7f2..ff0b0627 100755 --- a/app/models/nonprofit.rb +++ b/app/models/nonprofit.rb @@ -64,6 +64,7 @@ class Nonprofit < ApplicationRecord has_many :profiles, through: :donations has_many :campaigns, dependent: :destroy has_many :events, dependent: :destroy + has_many :object_event_hook_configs, dependent: :destroy has_many :tickets, through: :events has_many :roles, as: :host, dependent: :destroy has_many :users, through: :roles diff --git a/app/models/object_event_hook_config.rb b/app/models/object_event_hook_config.rb new file mode 100644 index 00000000..35d14c80 --- /dev/null +++ b/app/models/object_event_hook_config.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later +# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE +class ObjectEventHookConfig < ApplicationRecord + + # :webhook_service, #str, webhook service to be called + # :configuration, #jsonb, configuration needed to connect to the webhook + # :object_event_types, #text (array), a set of object event types + + belongs_to :nonprofit + + validates :webhook_service, presence: true + validates :configuration, presence: true + validates :object_event_types, presence: true + + serialize :object_event_types, Array + + WEBHOOK = { + open_fn: 'open_fn' + }.freeze + + def webhook + case webhook_service + when WEBHOOK[:open_fn] + Houdini::WebhookAdapter::OpenFn.new(configuration) + end + end +end diff --git a/db/migrate/20210209002832_create_object_event_hook_configs.rb b/db/migrate/20210209002832_create_object_event_hook_configs.rb new file mode 100644 index 00000000..efa5c1c9 --- /dev/null +++ b/db/migrate/20210209002832_create_object_event_hook_configs.rb @@ -0,0 +1,13 @@ +class CreateObjectEventHookConfigs < ActiveRecord::Migration[6.1] + def change + create_table :object_event_hook_configs do |t| + t.string :webhook_service, null: false + t.jsonb :configuration, null: false + t.text :object_event_types, null: false + + t.references :nonprofit, index: true, foreign_key: true, null: false + + t.timestamps + end + end +end diff --git a/db/structure.sql b/db/structure.sql index 81771875..21b94f06 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1586,6 +1586,40 @@ CREATE SEQUENCE public.nonprofits_id_seq ALTER SEQUENCE public.nonprofits_id_seq OWNED BY public.nonprofits.id; +-- +-- Name: object_event_hook_configs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.object_event_hook_configs ( + id bigint NOT NULL, + webhook_service character varying NOT NULL, + configuration jsonb NOT NULL, + object_event_types text NOT NULL, + nonprofit_id bigint NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: object_event_hook_configs_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.object_event_hook_configs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: object_event_hook_configs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.object_event_hook_configs_id_seq OWNED BY public.object_event_hook_configs.id; + + -- -- Name: offsite_payments; Type: TABLE; Schema: public; Owner: - -- @@ -2683,6 +2717,13 @@ ALTER TABLE ONLY public.nonprofit_keys ALTER COLUMN id SET DEFAULT nextval('publ ALTER TABLE ONLY public.nonprofits ALTER COLUMN id SET DEFAULT nextval('public.nonprofits_id_seq'::regclass); +-- +-- Name: object_event_hook_configs id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.object_event_hook_configs ALTER COLUMN id SET DEFAULT nextval('public.object_event_hook_configs_id_seq'::regclass); + + -- -- Name: offsite_payments id; Type: DEFAULT; Schema: public; Owner: - -- @@ -3160,6 +3201,14 @@ ALTER TABLE ONLY public.nonprofits ADD CONSTRAINT npos_pkey PRIMARY KEY (id); +-- +-- Name: object_event_hook_configs object_event_hook_configs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.object_event_hook_configs + ADD CONSTRAINT object_event_hook_configs_pkey PRIMARY KEY (id); + + -- -- Name: offsite_payments offsite_payments_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -3517,6 +3566,13 @@ CREATE INDEX index_modern_campaign_gifts_on_campaign_gift_purchase_id ON public. CREATE INDEX index_modern_donations_on_donation_id ON public.modern_donations USING btree (donation_id); +-- +-- Name: index_object_event_hook_configs_on_nonprofit_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_object_event_hook_configs_on_nonprofit_id ON public.object_event_hook_configs USING btree (nonprofit_id); + + -- -- Name: index_payments_on_created_at; Type: INDEX; Schema: public; Owner: - -- @@ -3841,6 +3897,14 @@ ALTER TABLE ONLY public.modern_campaign_gifts ADD CONSTRAINT fk_rails_0757cd7020 FOREIGN KEY (campaign_gift_id) REFERENCES public.campaign_gifts(id); +-- +-- Name: object_event_hook_configs fk_rails_10d2fb51c8; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.object_event_hook_configs + ADD CONSTRAINT fk_rails_10d2fb51c8 FOREIGN KEY (nonprofit_id) REFERENCES public.nonprofits(id); + + -- -- Name: ticket_purchases fk_rails_28d2157787; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -4404,11 +4468,12 @@ INSERT INTO "schema_migrations" (version) VALUES ('20210122203303'), ('20210127193411'), ('20210128215402'), +('20210204013426'), ('20210204172319'), -('20210204174909'), ('20210204210627'), ('20210204223643'), ('20210208211655'), -('20210208212655'); +('20210208212655'), +('20210209002832'); diff --git a/gems/bess/lib/houdini/webhook_adapter.rb b/gems/bess/lib/houdini/webhook_adapter.rb index 1dfbd95b..cdd99a07 100644 --- a/gems/bess/lib/houdini/webhook_adapter.rb +++ b/gems/bess/lib/houdini/webhook_adapter.rb @@ -6,17 +6,17 @@ class Houdini::WebhookAdapter autoload :OpenFn - attr_accessor :url, :auth_headers + attr_accessor :webhook_url, :headers def initialize(attributes={}) assign_attributes(attributes) if attributes end - def post(payload) + def transmit(payload) RestClient::Request.execute( method: :post, - url: url, + url: webhook_url, payload: payload, - headers: auth_headers + headers: headers ) end end diff --git a/spec/factories/object_event_hook_configs.rb b/spec/factories/object_event_hook_configs.rb new file mode 100644 index 00000000..5e3be87f --- /dev/null +++ b/spec/factories/object_event_hook_configs.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later +# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE +FactoryBot.define do + factory :open_fn_config, class: ObjectEventHookConfig do + webhook_service { :open_fn } + configuration do + { + webhook_url: 'https://www.openfn.org/inbox/my-inbox-id', + headers: { 'x-api-key': 'my-secret-key' } + } + end + object_event_types { ['supporter.update'] } + end +end diff --git a/spec/models/object_event_hook_config_spec.rb b/spec/models/object_event_hook_config_spec.rb new file mode 100644 index 00000000..9b10f666 --- /dev/null +++ b/spec/models/object_event_hook_config_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later +# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE +require 'rails_helper' + +RSpec.describe ObjectEventHookConfig, type: :model do + let(:nonprofit) { create(:nm_justice) } + let(:open_fn_config) { create(:open_fn_config, nonprofit_id: nonprofit.id) } + + describe '.webhook' do + it 'returns an instance of OpenFn webhook' do + webhook = double + expect(Houdini::WebhookAdapter::OpenFn) + .to receive(:new) + .and_return(webhook) + .with(open_fn_config.configuration) + result = open_fn_config.webhook + expect(result).to eq(webhook) + end + end +end