webhookr 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](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'
|