Merge pull request #115 from j-wilkins/webhook_agent

a webhook agent to create events from webhooks.

Andrew Cantino 11 years ago
parent
commit
8fde7492ca
2 changed files with 95 additions and 0 deletions
  1. 62 0
      app/models/agents/webhook_agent.rb
  2. 33 0
      spec/models/agents/webhook_agent_spec.rb

+ 62 - 0
app/models/agents/webhook_agent.rb

@@ -0,0 +1,62 @@
1
+module Agents
2
+  class WebhookAgent < Agent
3
+    cannot_be_scheduled!
4
+
5
+    description  do
6
+        <<-MD
7
+        Use this Agent to create events by receiving webhooks from any source.
8
+
9
+        In order to create events with this agent, make a POST request to:
10
+        ```
11
+           https://#{ENV['DOMAIN']}/users/#{user.id}/webhooks/#{id || '<id>'}/:secret
12
+        ``` where `:secret` is specified in your options.
13
+
14
+        The
15
+
16
+        Options:
17
+
18
+          * `secret` - A token that the host will provide for authentication.
19
+          * `expected_receive_period_in_days` - How often you expect to receive
20
+            events this way. Used to determine if the agent is working.
21
+          * `payload_path` - JSONPath of the attribute of the POST body to be
22
+            used as the Event payload.
23
+      MD
24
+    end
25
+
26
+    event_description do
27
+      <<-MD
28
+        The event payload is base on the value of the `payload_path` option,
29
+        which is set to `#{options[:payload_path]}`.
30
+      MD
31
+    end
32
+
33
+    def default_options
34
+      { "secret" => "supersecretstring",
35
+        "expected_receive_period_in_days" => 1,
36
+        "payload_path" => "payload"}
37
+    end
38
+
39
+    def receive_webhook(params)
40
+      secret = params.delete(:secret)
41
+      return ["Not Authorized", 401] unless secret == options[:secret]
42
+
43
+      create_event(:payload => payload_for(params))
44
+
45
+      ['Event Created', 201]
46
+    end
47
+
48
+    def working?
49
+      event_created_within(options[:expected_receive_period_in_days]) && !recent_error_logs?
50
+    end
51
+
52
+    def validate_options
53
+      unless options[:secret].present?
54
+        errors.add(:base, "Must specify a :secret for 'Authenticating' requests")
55
+      end
56
+    end
57
+
58
+    def payload_for(params)
59
+      Utils.values_at(params, options[:payload_path]) || {}
60
+    end
61
+  end
62
+end

+ 33 - 0
spec/models/agents/webhook_agent_spec.rb

@@ -0,0 +1,33 @@
1
+require 'spec_helper'
2
+
3
+describe Agents::WebhookAgent do
4
+  let(:agent) do
5
+    _agent = Agents::WebhookAgent.new(:name => 'webhook',
6
+             :options => {:secret => :foobar, :payload_path => '$'})
7
+    _agent.user = users(:bob)
8
+    _agent.save!
9
+    _agent
10
+  end
11
+  let(:payload) { {'some' => 'info'} }
12
+
13
+  after { agent.destroy }
14
+
15
+  describe 'receive_webhook' do
16
+    it 'should create event if secret matches' do
17
+      out = nil
18
+      lambda {
19
+        out = agent.receive_webhook({:secret => :foobar, :payload => payload})
20
+      }.should change { Event.count }.by(1)
21
+      out.should eq(['Event Created', 201])
22
+      Event.last.payload.should eq([{'payload' => payload}])
23
+    end
24
+
25
+    it 'should not create event if secrets dont match' do
26
+      out = nil
27
+      lambda {
28
+        out = agent.receive_webhook({:secret => :bazbat, :payload => payload})
29
+      }.should change { Event.count }.by(0)
30
+      out.should eq(['Not Authorized', 401])
31
+    end
32
+  end
33
+end