webhookr 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +14 -0
- data/Gemfile +18 -0
- data/Guardfile +31 -0
- data/MIT-LICENSE +22 -0
- data/README.md +159 -0
- data/Rakefile +46 -0
- data/app/controllers/webhookr/events_controller.rb +34 -0
- data/config/routes.rb +4 -0
- data/lib/generators/webhookr/add_route_generator.rb +12 -0
- data/lib/generators/webhookr/init_generator.rb +30 -0
- data/lib/tasks/webhookr_tasks.rake +16 -0
- data/lib/webhookr/adapter_response.rb +3 -0
- data/lib/webhookr/engine.rb +16 -0
- data/lib/webhookr/invalid_payload_error.rb +3 -0
- data/lib/webhookr/invalid_security_token_error.rb +3 -0
- data/lib/webhookr/ostruct_utils.rb +28 -0
- data/lib/webhookr/service.rb +51 -0
- data/lib/webhookr/services/adapter/base.rb +20 -0
- data/lib/webhookr/services/adapter.rb +7 -0
- data/lib/webhookr/services.rb +7 -0
- data/lib/webhookr/version.rb +3 -0
- data/lib/webhookr.rb +24 -0
- data/script/rails +8 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +65 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +31 -0
- data/test/dummy/config/environments/production.rb +64 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/webhookr.rb +2 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +10 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/functional/webhookr/events_controller_test.rb +76 -0
- data/test/functional/webhookr/events_routes_test.rb +33 -0
- data/test/functional/webhookr/service_test.rb +91 -0
- data/test/integration/webhookr/add_route_generator_test.rb +15 -0
- data/test/integration/webhookr/init_generator_test.rb +27 -0
- data/test/stubs/service_under_test_stubs.rb +73 -0
- data/test/test_helper.rb +18 -0
- data/test/unit/webhookr/Services/ServiceUnderTest/adapter_test.rb +39 -0
- data/test/unit/webhookr/adapter_response_test.rb +20 -0
- data/test/unit/webhookr/ostruct_utils_test.rb +32 -0
- data/test/webhookr_test.rb +11 -0
- data/webhookr.gemspec +22 -0
- metadata +171 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
gem "rake", "~> 10.0"
|
6
|
+
gem "minitest"
|
7
|
+
gem "minitest-reporters"
|
8
|
+
gem "em-websocket"
|
9
|
+
gem "guard"
|
10
|
+
gem "guard-minitest"
|
11
|
+
gem "guard-markdown"
|
12
|
+
gem "guard-livereload"
|
13
|
+
gem "simplecov", :require => false
|
14
|
+
|
15
|
+
if File.exists?('Gemfile.local')
|
16
|
+
instance_eval File.read('Gemfile.local')
|
17
|
+
end
|
18
|
+
|
data/Guardfile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
guard 'minitest', :test_folders => 'test', :test_file_patterns => '*_test.rb' do
|
3
|
+
watch(%r|^test/(.+)_test\.rb|)
|
4
|
+
watch(%r|^test/stubs/(.+)\.rb$|) { "test" }
|
5
|
+
|
6
|
+
# Rails
|
7
|
+
watch(%r{^app/models/(.+)\.rb$}) { |m|
|
8
|
+
"test/unit/#{m[1]}_test.rb"
|
9
|
+
}
|
10
|
+
|
11
|
+
watch(%r{^app/controllers/(.+)\.rb$}) { |m|
|
12
|
+
"test/functional/#{m[1]}_test.rb"
|
13
|
+
}
|
14
|
+
|
15
|
+
watch('config/routes.rb') {
|
16
|
+
["test/functional", "test/integration"]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
guard 'livereload' do
|
21
|
+
watch('README.md')
|
22
|
+
end
|
23
|
+
|
24
|
+
guard 'markdown', :convert_on_start => true do
|
25
|
+
watch ('README.md') { "./README.md|./README.html" }
|
26
|
+
end
|
27
|
+
|
28
|
+
if File.exists?('Guardfile.local')
|
29
|
+
instance_eval File.read('Guardfile.local')
|
30
|
+
end
|
31
|
+
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 2167961 Ontario Inc., Zoocasa <code@zoocasa.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# webhookr: Rails Webhooks Made Easy
|
2
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/zoocasa/webhookr)
|
3
|
+
|
4
|
+
## <a name="introduction"></a>Introduction
|
5
|
+
|
6
|
+
### What is webhookr?
|
7
|
+
|
8
|
+
webhookr is a Rails Engine that easily and securely adds third-party
|
9
|
+
webhooks to your Rails app. It supports third-party sites with modular
|
10
|
+
plugins.
|
11
|
+
|
12
|
+
### What are 'webhooks'?
|
13
|
+
|
14
|
+
From 30,000 feet, webhooks allow disparate cloud services to coordinate and
|
15
|
+
asynchronously notify each other of events of interest. For example, a shopping app might
|
16
|
+
want to process a [customer credit card transaction](https://stripe.com/docs/webhooks),
|
17
|
+
and be notified of success or failure.
|
18
|
+
|
19
|
+
From 10,000 feet, webhooks allow external third parties the ability to
|
20
|
+
execute code within your application, using a well defined message exchange
|
21
|
+
protocol.
|
22
|
+
|
23
|
+
From 1,000 feet and below, webhooks are application routes and controller
|
24
|
+
endpoints, third-party API discovery, security decisions, and code that
|
25
|
+
executes within your application.
|
26
|
+
|
27
|
+
|
28
|
+
### Why use webhookr?
|
29
|
+
|
30
|
+
Webhooks are http callbacks from another service that are useful for
|
31
|
+
pushing information to your Rails application. The question is: How do I
|
32
|
+
easily and securely add them to my Rails application?
|
33
|
+
|
34
|
+
webhookr provides a single, secure route for all your webhooks, and uses
|
35
|
+
the observer pattern to integrate the webhook with your business logic.
|
36
|
+
Using webhookr you can be up and running with a third-party webhook in less
|
37
|
+
than an hour.
|
38
|
+
|
39
|
+
### How does webhookr work?
|
40
|
+
|
41
|
+
Webhookr provides a standard approach for third-party webhooks via plugins. The
|
42
|
+
author of a plugin implements code to standardize any webhook into an action and
|
43
|
+
data packet. Your task is to write glue code that is called whenever an action is
|
44
|
+
received, and to use the resulting data packet for your application logic. Here is
|
45
|
+
a subset of the MailChimp handler that might be written to deal with the 'unsubscribe'
|
46
|
+
action sent from MailChimp:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
class MailChimpHooks
|
50
|
+
def on_unsubscribe(payload)
|
51
|
+
User.unsubscribe_newletter(payload.data.email)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
## <a name="usage"></a>Usage & Setup
|
57
|
+
|
58
|
+
webhookr works with Rails 3.1 onwards. It generally requires a plugin to be
|
59
|
+
useful, such as the [MailChimp plugin](https://github.com/zoocasa/webhookr-mailchimp).
|
60
|
+
|
61
|
+
## Setup
|
62
|
+
|
63
|
+
Add webhookr to your Gemfile with:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
gem 'webhookr'
|
67
|
+
```
|
68
|
+
|
69
|
+
Run the bundle command to install it and then run the generator to
|
70
|
+
add the engine route to your config/routes.rb:
|
71
|
+
|
72
|
+
```console
|
73
|
+
rails g webhookr:add_route
|
74
|
+
```
|
75
|
+
|
76
|
+
or, add the routing information manually to config/routes.rb
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
mount Webhookr::Engine => "/webhookr", :as => "webhookr"
|
80
|
+
```
|
81
|
+
|
82
|
+
The initialization file for webhookr is optional. To see what
|
83
|
+
options are available, you can run the generator and review the
|
84
|
+
sample config file:
|
85
|
+
|
86
|
+
```console
|
87
|
+
rails g webhookr:init *initializer_name*
|
88
|
+
```
|
89
|
+
|
90
|
+
Once you have added third-party plugins, you can use the provided
|
91
|
+
rake task to output your applications urls for each service:
|
92
|
+
|
93
|
+
```console
|
94
|
+
rake webhookr:services
|
95
|
+
```
|
96
|
+
|
97
|
+
## <a name="security"></a>Webhookr Security
|
98
|
+
|
99
|
+
### General security issues with webhooks
|
100
|
+
|
101
|
+
A webhook is by design, a http post to your application that results in code execution.
|
102
|
+
Having a well defined approach to adding such functionality can help ensure you don't open security issues
|
103
|
+
within your application.
|
104
|
+
|
105
|
+
Many webhook providers do not provide built-in security for their
|
106
|
+
webhooks - they usually send the post over http, and they often have no authentication
|
107
|
+
or verification mechanism. If your webhook third-party service responds to hooks, it is
|
108
|
+
possible for an evil person to guess your webhook URL, and attempt to wreak havoc with your system.
|
109
|
+
|
110
|
+
### How using webhookr can increase security
|
111
|
+
webhookr provides a unique url for each service, via a security token that is used in the webhook path, to help make it hard to guess your webhook url.
|
112
|
+
For example, if you were using MailChimp, your webhook url might look like: '/webhookr/mailchimp/cdd2a24cfac821' and if you were using Mandrill, your
|
113
|
+
webhook might look like: '/webhookr/mandrill/de69557a4d95e7'. This will help prevent someone guessing your
|
114
|
+
webhook service url. If you are using https, the URL will be encrypted, keeping your security token a secret.
|
115
|
+
|
116
|
+
You can also enable http basic auth, if the third party service supports it. Note that enabling http basic auth
|
117
|
+
affects all your webhooks, so be sure it is supported by all your third-party services.
|
118
|
+
|
119
|
+
If you are sending sensitive data via webhooks, it is recommended you use HTTPS.
|
120
|
+
|
121
|
+
### <a name="supported_services"></a>Supported Services
|
122
|
+
|
123
|
+
* MailChimp - webhookr-mail_chimp
|
124
|
+
* Mandrill - webhookr-mandrill
|
125
|
+
* Github - coming soon
|
126
|
+
* Stripe - coming soon
|
127
|
+
|
128
|
+
## <a name="works_with"></a>Works with:
|
129
|
+
|
130
|
+
webhookr works with Rails 3.1 and 3.2, and has been tested on the following Ruby
|
131
|
+
implementations:
|
132
|
+
|
133
|
+
* JRuby 1.7.1
|
134
|
+
* MRI 1.8.7
|
135
|
+
* MRI 1.9.2
|
136
|
+
* MRI 1.9.3
|
137
|
+
* Rubinius 1.2.4
|
138
|
+
* Ruby EE 1.8.7
|
139
|
+
|
140
|
+
Pending:
|
141
|
+
|
142
|
+
* MRI 2.0
|
143
|
+
|
144
|
+
### TODO
|
145
|
+
* Implement get/post strategies and responses so the controller can return variable text to the service.
|
146
|
+
This allows support for advanced Webhook responses for services that require it.
|
147
|
+
* Enhance testing of Rake tasks
|
148
|
+
* Clean up the stubs with FactoryGirl
|
149
|
+
* Test with MRI 2.0
|
150
|
+
|
151
|
+
### License
|
152
|
+
|
153
|
+
webhookr is released under the [MIT license](http://www.opensource.org/licenses/MIT).
|
154
|
+
|
155
|
+
## Author
|
156
|
+
|
157
|
+
* [Gerry Power](https://github.com/gerrypower)
|
158
|
+
|
159
|
+
## <a name="Version History"></a>Version History
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rubygems/package_task'
|
6
|
+
require 'rake/testtask'
|
7
|
+
require 'rdoc/task'
|
8
|
+
require 'bundler/gem_tasks'
|
9
|
+
|
10
|
+
$:.push File.expand_path(File.dirname(__FILE__), 'lib')
|
11
|
+
|
12
|
+
version = Webhookr::VERSION
|
13
|
+
|
14
|
+
desc 'Test Webhookr'
|
15
|
+
Rake::TestTask.new(:test) do |t|
|
16
|
+
t.test_files = FileList['test/**/*_test.rb']
|
17
|
+
t.verbose = !!ENV['VERBOSE_TESTS']
|
18
|
+
t.warning = !!ENV['WARNINGS']
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Build docs'
|
22
|
+
Rake::RDocTask.new do |t|
|
23
|
+
t.main = 'README.md'
|
24
|
+
t.title = "Webhookr #{version}"
|
25
|
+
t.rdoc_dir = 'doc'
|
26
|
+
t.rdoc_files.include('README.md', 'MIT-LICENSE', 'lib/**/*.rb')
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :webhookr do
|
30
|
+
namespace:test do
|
31
|
+
desc 'Install gems in all Rubies'
|
32
|
+
task :install do
|
33
|
+
sh %{rbenv each -v bundle install}
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'Test with all Rubies'
|
37
|
+
task :test_versions do
|
38
|
+
sh %{rbenv each -v bundle exec rake test}
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Install and test all'
|
42
|
+
task :all => [:install, :test_versions]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
task :default => :test
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Webhookr
|
2
|
+
class EventsController < ActionController::Base
|
3
|
+
http_basic_authenticate_with(
|
4
|
+
:name => Webhookr.config.basic_auth.username,
|
5
|
+
:password => Webhookr.config.basic_auth.password
|
6
|
+
) if Webhookr.config.basic_auth.username && Webhookr.config.basic_auth.password
|
7
|
+
|
8
|
+
before_filter :create_service
|
9
|
+
|
10
|
+
def show
|
11
|
+
render :nothing => true
|
12
|
+
end
|
13
|
+
|
14
|
+
def create
|
15
|
+
@service.process!
|
16
|
+
render :nothing => true
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def create_service
|
22
|
+
begin
|
23
|
+
@service = Webhookr::Service.new(
|
24
|
+
params[:service_id], :payload => request.body.read, :security_token => params[:security_token]
|
25
|
+
)
|
26
|
+
rescue NameError => e
|
27
|
+
raise ActionController::RoutingError.new("No service '#{params[:service_id]}' is available.")
|
28
|
+
rescue Webhookr::InvalidSecurityTokenError => e
|
29
|
+
raise ActionController::InvalidAuthenticityToken.new("Invalid or missing security token for service '#{params[:service_id]}'.")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Webhookr
|
2
|
+
module Generators
|
3
|
+
class AddRouteGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
desc 'This generator adds \'mount Webhookr::Engine => "/webhookr", :as => "webhookr"\' to your routes'
|
6
|
+
def add_route
|
7
|
+
route 'mount Webhookr::Engine => "/webhookr", :as => "webhookr"'
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Webhookr
|
2
|
+
module Generators
|
3
|
+
class InitGenerator < Rails::Generators::NamedBase
|
4
|
+
|
5
|
+
desc "This generator creates an initializer file 'config/initializers/NAME.rb'"
|
6
|
+
def init
|
7
|
+
initializer("#{file_name}.rb") do
|
8
|
+
file_contents
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def file_contents
|
13
|
+
<<-eos
|
14
|
+
# Webhookr Initializer
|
15
|
+
|
16
|
+
## Turn on http basic authentication for all plugins
|
17
|
+
# Webhookr.config.basic_auth.username = "admin"
|
18
|
+
# Webhookr.config.basic_auth.password = "password"
|
19
|
+
|
20
|
+
## Plugin Initializers go here ##
|
21
|
+
eos
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate_security_token
|
25
|
+
rand(10000000000000000).floor.to_s(36)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
namespace :webhookr do
|
2
|
+
desc "List the configured services and paths"
|
3
|
+
task :services => :environment do
|
4
|
+
|
5
|
+
puts "No webhookr services configured - add and configure webhookr plugins." and next if Webhookr.adapters.empty?
|
6
|
+
|
7
|
+
include Webhookr::Engine.routes.url_helpers
|
8
|
+
|
9
|
+
Webhookr.adapters.each do |key, adapter|
|
10
|
+
puts "\n\n#{key}:"
|
11
|
+
%w{ GET POST}.each do |x|
|
12
|
+
puts " #{x}\t#{events_path(key, :security_token => Webhookr.config[key].try(:security_token))}\n"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support/core_ext/kernel/singleton_class'
|
2
|
+
|
3
|
+
module Webhookr
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
isolate_namespace Webhookr
|
6
|
+
|
7
|
+
# Enable basic auth for all services when config.basic_auth.username
|
8
|
+
# and config.basic_auth.password are set.
|
9
|
+
self.config.webhookr = ActiveSupport::OrderedOptions.new
|
10
|
+
self.config.webhookr.basic_auth = ActiveSupport::OrderedOptions.new
|
11
|
+
|
12
|
+
initializer "webhookr.config" do |app|
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Webhookr
|
2
|
+
# Adapted from http://www.rebeccamiller-webster.com/2012/06/recursively-convert-a-ruby-hash-to-openstruct/
|
3
|
+
module OstructUtils
|
4
|
+
|
5
|
+
def self.to_ostruct(obj)
|
6
|
+
case
|
7
|
+
when obj.kind_of?(Hash)
|
8
|
+
return hash_to_ostruct(obj)
|
9
|
+
when obj.kind_of?(Array)
|
10
|
+
return array_to_ostruct(obj)
|
11
|
+
else
|
12
|
+
return obj
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.hash_to_ostruct(hash)
|
17
|
+
hash.each do |key, val|
|
18
|
+
hash[key] = to_ostruct(val)
|
19
|
+
end
|
20
|
+
OpenStruct.new(hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.array_to_ostruct(array)
|
24
|
+
array.map { |r| to_ostruct(r) }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Webhookr
|
2
|
+
class Service
|
3
|
+
attr_reader :service_name
|
4
|
+
|
5
|
+
def initialize(service_name, options = {})
|
6
|
+
@service_name = (service_name || "").downcase
|
7
|
+
@raw_payload = options[:payload]
|
8
|
+
available?
|
9
|
+
validate_security_token(options[:security_token]) if configured_security_token
|
10
|
+
end
|
11
|
+
|
12
|
+
def process!
|
13
|
+
Array.wrap(service_adapter.send(:process, @raw_payload)).each do |payload|
|
14
|
+
callback(callback_class, payload)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def callback(object, payload)
|
21
|
+
method = method_for(payload)
|
22
|
+
object.send(method, payload) if object.respond_to?(method)
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_for(payload)
|
26
|
+
"on_" + payload.event_type
|
27
|
+
end
|
28
|
+
|
29
|
+
def callback_class
|
30
|
+
callback = Webhookr.config[service_name].try(:callback)
|
31
|
+
raise "No callback is configured for the service '#{service_name}'." if callback.nil?
|
32
|
+
@call_back_class || callback.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def configured_security_token
|
36
|
+
Webhookr.config[service_name].try(:security_token)
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate_security_token(token)
|
40
|
+
raise Webhookr::InvalidSecurityTokenError if token.nil? || token != configured_security_token
|
41
|
+
end
|
42
|
+
|
43
|
+
def service_adapter
|
44
|
+
raise NameError.new(%{Bad service name "#{service_name}"}) unless Webhookr.adapters[service_name]
|
45
|
+
@service_adapter ||= Webhookr.adapters[service_name]
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_method :available?, :service_adapter
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
module Webhookr::Services::Adapter::Base
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
self.initialize! if self.respond_to?(:initialize!)
|
7
|
+
Webhookr.adapters[self::SERVICE_NAME] = self
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def config
|
12
|
+
if Webhookr.config[self::SERVICE_NAME]
|
13
|
+
Webhookr.config[self::SERVICE_NAME]
|
14
|
+
else
|
15
|
+
Webhookr.config[self::SERVICE_NAME] = ActiveSupport::OrderedOptions.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
data/lib/webhookr.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "webhookr/engine"
|
2
|
+
|
3
|
+
module Webhookr
|
4
|
+
extend ActiveSupport::Autoload
|
5
|
+
|
6
|
+
autoload :InvalidPayloadError
|
7
|
+
autoload :AdapterResponse
|
8
|
+
autoload :Service
|
9
|
+
autoload :VERSION
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def adapters
|
13
|
+
@adapters ||= HashWithIndifferentAccess.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def config
|
17
|
+
@config ||= defined?(Rails) ? Rails.application.config.webhookr :
|
18
|
+
ActiveSupport::OrderedOptions.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require "webhookr/services"
|
24
|
+
|
data/script/rails
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
5
|
+
ENGINE_PATH = File.expand_path('../../lib/webhookr/engine', __FILE__)
|
6
|
+
|
7
|
+
require 'rails/all'
|
8
|
+
require 'rails/engine/commands'
|