zapier_rest_hooks 0.0.1

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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +30 -0
  4. data/app/controllers/zapier_rest_hooks/application_controller.rb +5 -0
  5. data/app/controllers/zapier_rest_hooks/hooks_controller.rb +31 -0
  6. data/app/models/zapier_rest_hooks/hook.rb +37 -0
  7. data/config/routes.rb +3 -0
  8. data/db/migrate/20160614153212_create_zapier_rest_hooks_hooks.rb +11 -0
  9. data/db/migrate/20160614204418_add_owner_to_hooks.rb +6 -0
  10. data/lib/generators/zapier_rest_hooks/install_generator.rb +22 -0
  11. data/lib/tasks/zapier_rest_hooks_tasks.rake +4 -0
  12. data/lib/zapier_rest_hooks.rb +4 -0
  13. data/lib/zapier_rest_hooks/engine.rb +12 -0
  14. data/lib/zapier_rest_hooks/version.rb +3 -0
  15. data/spec/controllers/zapier_rest_hooks/hooks_controller_spec.rb +28 -0
  16. data/spec/dummy/README.rdoc +28 -0
  17. data/spec/dummy/Rakefile +6 -0
  18. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  19. data/spec/dummy/app/models/candidate.rb +20 -0
  20. data/spec/dummy/app/models/organization.rb +2 -0
  21. data/spec/dummy/bin/bundle +3 -0
  22. data/spec/dummy/bin/rails +4 -0
  23. data/spec/dummy/bin/rake +4 -0
  24. data/spec/dummy/bin/setup +29 -0
  25. data/spec/dummy/config.ru +4 -0
  26. data/spec/dummy/config/application.rb +31 -0
  27. data/spec/dummy/config/boot.rb +5 -0
  28. data/spec/dummy/config/database.yml +25 -0
  29. data/spec/dummy/config/environment.rb +5 -0
  30. data/spec/dummy/config/environments/development.rb +41 -0
  31. data/spec/dummy/config/environments/production.rb +79 -0
  32. data/spec/dummy/config/environments/test.rb +42 -0
  33. data/spec/dummy/config/initializers/assets.rb +11 -0
  34. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  36. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  37. data/spec/dummy/config/initializers/inflections.rb +16 -0
  38. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  39. data/spec/dummy/config/initializers/session_store.rb +3 -0
  40. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  41. data/spec/dummy/config/locales/en.yml +23 -0
  42. data/spec/dummy/config/routes.rb +3 -0
  43. data/spec/dummy/config/secrets.yml +22 -0
  44. data/spec/dummy/db/development.sqlite3 +0 -0
  45. data/spec/dummy/db/migrate/20160614170150_create_organizations.rb +9 -0
  46. data/spec/dummy/db/migrate/20160614170351_create_candidates.rb +11 -0
  47. data/spec/dummy/db/schema.rb +43 -0
  48. data/spec/dummy/db/test.sqlite3 +0 -0
  49. data/spec/dummy/log/development.log +13 -0
  50. data/spec/dummy/log/test.log +4887 -0
  51. data/spec/dummy/public/404.html +67 -0
  52. data/spec/dummy/public/422.html +67 -0
  53. data/spec/dummy/public/500.html +66 -0
  54. data/spec/dummy/public/favicon.ico +0 -0
  55. data/spec/factories/candidates.rb +8 -0
  56. data/spec/factories/hooks.rb +9 -0
  57. data/spec/factories/organizations.rb +5 -0
  58. data/spec/models/candidate_spec.rb +53 -0
  59. data/spec/models/zapier_rest_hooks/hook_spec.rb +102 -0
  60. data/spec/spec_helper.rb +39 -0
  61. data/spec/zapier_rest_hooks_spec.rb +7 -0
  62. metadata +321 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 38e5cbb5067871db89890b70f6e3973caa00a119
4
+ data.tar.gz: 4fe11ce016bbb4a59957dd220cf4529efa0ab67b
5
+ SHA512:
6
+ metadata.gz: 3e501fe2d7e89eb4249127f791b9ee1bc0b90ee6f1d4e742cf069c7763353e49faa1d89e7de2af203ffe7ec942cabe09e4d7745caae1a106ad65734022990645
7
+ data.tar.gz: 9481d479aa699e97d8def79110668890a17c6d8c4da422ce6b01f43ca661edc21574aa1a423c4adcfe41744236987c95f579a069e8bdc2297a56e018b2a685b7
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Esteban Arango Medina
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ZapierRestHooks'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rspec/core'
25
+ require 'rspec/core/rake_task'
26
+
27
+ desc 'Run all specs in spec directory (excluding plugin specs)'
28
+ RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
29
+
30
+ task default: :spec
@@ -0,0 +1,5 @@
1
+ module ZapierRestHooks
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,31 @@
1
+ require_dependency 'zapier_rest_hooks/application_controller'
2
+
3
+ module ZapierRestHooks
4
+ class HooksController < ApplicationController
5
+ def create
6
+ hook = Hook.new(hook_params)
7
+ render nothing: true, status: 500 && return unless hook.save
8
+ Rails.logger.info "Created REST hook: #{hook.inspect}"
9
+ # The Zapier documentation says to return 201 - Created.
10
+ render json: hook.to_json(only: :id), status: 201
11
+ end
12
+
13
+ def destroy
14
+ hook = Hook.find(params[:id]) if params[:id]
15
+ if hook.nil? && params[:subscription_url]
16
+ hook = Hook.find_by_subscription_url(params[:subscription_url]).destroy
17
+ end
18
+ Rails.logger.info "Destroying REST hook: #{hook.inspect}"
19
+ hook.destroy
20
+ render nothing: true, status: 200
21
+ end
22
+
23
+ private
24
+
25
+ def hook_params
26
+ params[:event_name] ||= params[:name]
27
+ params[:hook] = params
28
+ params.require(:hook).permit(:event_name, :target_url, :owner_id, :owner_class_name, :subscription_url)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ require 'rest-client'
2
+ module ZapierRestHooks
3
+ Struct.new('ZapierApp', :id)
4
+ class Hook < ActiveRecord::Base
5
+ validates :event_name, :target_url, presence: true
6
+
7
+ # Looks for an appropriate REST hook that matches the owner, and triggers the hook if one exists.
8
+ def self.trigger(event_name, encoded_record, owner = Struct::ZapierApp.new(0))
9
+ hooks = self.hooks(event_name, owner)
10
+ return if hooks.empty?
11
+
12
+ unless Rails.env.development?
13
+ # Trigger each hook if there is more than one for an owner, which can happen.
14
+ hooks.each do |hook|
15
+ Rails.logger.info "Triggering REST hook event: #{event_name} / #{hook.inspect}"
16
+ Rails.logger.info "REST hook record: #{encoded_record}"
17
+ RestClient.post(hook.target_url, encoded_record) do |response|
18
+ if response.code.eql? 410
19
+ Rails.logger.info "Destroying REST hook because of 410 response: #{hook.inspect}"
20
+ hook.destroy
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ # Returns all hooks for a given event_name and owner.
28
+ def self.hooks(event_name, owner = Struct::ZapierApp.new(0))
29
+ where(event_name: event_name, owner_class_name: owner.class.name, owner_id: owner.id)
30
+ end
31
+
32
+ # Tests whether any hooks exist for a given event_name and owner
33
+ def self.hooks_exist?(event_name, owner = Struct::ZapierApp.new(0))
34
+ hooks(event_name, owner).any?
35
+ end
36
+ end
37
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ ZapierRestHooks::Engine.routes.draw do
2
+ resources :hooks, only: [:create, :destroy]
3
+ end
@@ -0,0 +1,11 @@
1
+ class CreateZapierRestHooksHooks < ActiveRecord::Migration
2
+ def change
3
+ create_table :zapier_rest_hooks_hooks do |t|
4
+ t.string :event_name
5
+ t.string :subscription_url
6
+ t.string :target_url
7
+
8
+ t.timestamps null: false
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ class AddOwnerToHooks < ActiveRecord::Migration
2
+ def change
3
+ add_column :zapier_rest_hooks_hooks, :owner_id, :string, default: 0
4
+ add_column :zapier_rest_hooks_hooks, :owner_class_name, :string, default: 'Struct::ZapierApp'
5
+ end
6
+ end
@@ -0,0 +1,22 @@
1
+
2
+ require 'rails/generators/base'
3
+ module ZapierRestHooks
4
+ class InstallGenerator < Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+ source_root File.expand_path('../templates', __FILE__)
7
+ require 'rails/generators/migration'
8
+
9
+ desc 'Mounts ZapierRestHooks in routes and copies migrations.'
10
+
11
+ def mount_in_routes
12
+ route 'mount ZapierRestHooks::Engine, at: "/hooks"'
13
+ end
14
+
15
+ def copy_migrations
16
+ require 'rake'
17
+ Rails.application.load_tasks
18
+ Rake::Task['railties:install:migrations'].reenable
19
+ Rake::Task['zapier_rest_hooks:install:migrations'].invoke
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :zapier_rest_hooks do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,4 @@
1
+ require 'zapier_rest_hooks/engine'
2
+
3
+ module ZapierRestHooks
4
+ end
@@ -0,0 +1,12 @@
1
+ module ZapierRestHooks
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace ZapierRestHooks
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec, fixture: false
7
+ g.fixture_replacement :factory_girl, dir: 'spec/factories'
8
+ g.assets false
9
+ g.helper false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module ZapierRestHooks
2
+ VERSION = '0.0.1'.freeze
3
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module ZapierRestHooks
4
+ RSpec.describe HooksController, type: :controller do
5
+ routes { ZapierRestHooks::Engine.routes }
6
+
7
+ before :each do
8
+ request.env['HTTP_ACCEPT'] = 'application/json'
9
+ end
10
+
11
+ describe 'POST #create' do
12
+ it 'creates a new hook' do
13
+ expect {
14
+ post :create, attributes_for(:hook)
15
+ }.to change(Hook, :count).by(1)
16
+ end
17
+ end
18
+
19
+ describe 'DELETE #destroy' do
20
+ let!(:hook) { create(:hook) }
21
+ it 'destroys the requested font' do
22
+ expect {
23
+ delete :destroy, id: hook
24
+ }.to change(Hook, :count).by(-1)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,20 @@
1
+ class Candidate < ActiveRecord::Base
2
+ # Relations
3
+ belongs_to :organization
4
+
5
+ # Callbacks
6
+ after_create :trigger_hooks_with_owner, if: :organization
7
+ after_create :trigger_hooks_without_owner, unless: :organization
8
+
9
+ private
10
+
11
+ def trigger_hooks_with_owner
12
+ return unless ZapierRestHooks::Hook.hooks_exist?('new_candidate', organization)
13
+ ZapierRestHooks::Hook.trigger('new_candidate', to_json, organization)
14
+ end
15
+
16
+ def trigger_hooks_without_owner
17
+ return unless ZapierRestHooks::Hook.hooks_exist?('new_candidate')
18
+ ZapierRestHooks::Hook.trigger('new_candidate', to_json)
19
+ end
20
+ end
@@ -0,0 +1,2 @@
1
+ class Organization < ActiveRecord::Base
2
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ # path to your application root.
5
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6
+
7
+ Dir.chdir APP_ROOT do
8
+ # This script is a starting point to setup your application.
9
+ # Add necessary setup steps to this file:
10
+
11
+ puts "== Installing dependencies =="
12
+ system "gem install bundler --conservative"
13
+ system "bundle check || bundle install"
14
+
15
+ # puts "\n== Copying sample files =="
16
+ # unless File.exist?("config/database.yml")
17
+ # system "cp config/database.yml.sample config/database.yml"
18
+ # end
19
+
20
+ puts "\n== Preparing database =="
21
+ system "bin/rake db:setup"
22
+
23
+ puts "\n== Removing old logs and tempfiles =="
24
+ system "rm -f log/*"
25
+ system "rm -rf tmp/cache"
26
+
27
+ puts "\n== Restarting application server =="
28
+ system "touch tmp/restart.txt"
29
+ end
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Rails.application
@@ -0,0 +1,31 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ # Pick the frameworks you want:
4
+ require 'active_record/railtie'
5
+ require 'action_controller/railtie'
6
+ require 'action_mailer/railtie'
7
+ require 'action_view/railtie'
8
+ require 'sprockets/railtie'
9
+ # require 'rails/test_unit/railtie'
10
+
11
+ Bundler.require(*Rails.groups)
12
+ require 'zapier_rest_hooks'
13
+
14
+ module Dummy
15
+ class Application < Rails::Application
16
+ # Settings in config/environments/* take precedence over those specified here.
17
+ # Application configuration should go into files in config/initializers
18
+ # -- all .rb files in that directory are automatically loaded.
19
+
20
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
21
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
22
+ # config.time_zone = 'Central Time (US & Canada)'
23
+
24
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
25
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
26
+ # config.i18n.default_locale = :de
27
+
28
+ # Do not swallow errors in after_commit/after_rollback callbacks.
29
+ config.active_record.raise_in_transactional_callbacks = true
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
@@ -0,0 +1,25 @@
1
+ # SQLite version 3.x
2
+ # gem install sqlite3
3
+ #
4
+ # Ensure the SQLite 3 gem is defined in your Gemfile
5
+ # gem 'sqlite3'
6
+ #
7
+ default: &default
8
+ adapter: sqlite3
9
+ pool: 5
10
+ timeout: 5000
11
+
12
+ development:
13
+ <<: *default
14
+ database: db/development.sqlite3
15
+
16
+ # Warning: The database defined as "test" will be erased and
17
+ # re-generated from your development database when you run "rake".
18
+ # Do not set this db to the same as development or production.
19
+ test:
20
+ <<: *default
21
+ database: db/test.sqlite3
22
+
23
+ production:
24
+ <<: *default
25
+ database: db/production.sqlite3