the_captain_rails 2.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 067e4917ab8718f6a09759d82038125d823b7f26c2b89a961930045f9d400426
4
+ data.tar.gz: 79d157124ef0a1b7709dd73d5503cbfc2e4b7cb140be100c146ed169589703cc
5
+ SHA512:
6
+ metadata.gz: dd80b45095569decb676aea7afa7e9bdd5e8ef0052774ff95d64d759201d20780b3e41ea127ffb8383d0d87f671f98ebf8cb08a1795272b6de9da4dbed3ec5a1
7
+ data.tar.gz: e5ae2c72bca3c5a93560bbf1a9e9005bbdacafb9a60ed4fcc290de4a32605024c0a796074362642116584e739d4698b540c59fb6e53867f18b08dc3c67d5a364
@@ -0,0 +1,85 @@
1
+ # TheCaptain Rails
2
+ The gist is that this is housing Rail's specific logic for handling Captain responses and submissions in a Rails project.
3
+
4
+ Main core feature is the ability to subscribe / explicitly listen for Webhooks that a developer would like to Handel in a specific manner.
5
+
6
+ I.E. If a Webhook comes back for an IP or Content analysis. A developer may want to allow specific class handlers to manage / analyze these pieces of information differently and directed to other parts of the application.
7
+
8
+ (AKA: Single Responsibility Rule)
9
+
10
+ ## Usage
11
+
12
+
13
+ ## Installation
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem "the_captain", git: "https://github.com/VianetManagement/the-captain-ruby.git", branch: "3.0.0"
18
+ gem 'the_captain_rails', git: "https://github.com/VianetManagement/the-captain-rails"
19
+ ```
20
+
21
+
22
+ ## Configuration
23
+
24
+ ### Webhook events
25
+
26
+ #### Configuring The Rails Router Path
27
+
28
+ Ensure we mount the controller path to handel requests.
29
+
30
+ `/config/routes.rb`
31
+ ```ruby
32
+ Rails.application.routes.draw do
33
+ mount TheCaptain::Events::Engine => "/captain/events"
34
+ # ....
35
+ end
36
+ ```
37
+
38
+ Your webhook endpoint will look something like `http://[HOST]/captain/events`
39
+
40
+ #### Configuring Webhook Listeners
41
+
42
+ `/config/initializer/the_captain.rb`
43
+
44
+ ```ruby
45
+ TheCaptain::Event.configure do |config|
46
+ config.subscribe("Account Abuse") { |event| ... }
47
+
48
+ # Alternatively you can also define a class that contains a `call/1` method
49
+ config.subscribe("Account Abuse", AccountManagment::Abuse.new)
50
+
51
+ # If you wish for all events to pass through a single entry point or you want to log something about any webhook
52
+ # passthrough
53
+ config.all { |event| ... }
54
+
55
+ # [again] Alternatively you can also define a class that contains a `call/1` method
56
+ config.all WebhookManager.new
57
+ end
58
+ ```
59
+
60
+ Be default the `.subscribe/2` method will listen and attempt to parse which **Kit Name** triggered the given webhook.
61
+
62
+ You can modify the listening key by configuring the `.event_key_filter/1`
63
+
64
+ ```ruby
65
+
66
+ TheCaptain::Event.configure do |config|
67
+ config.event_key_filter = proc { |event| event.[some_key_value_in_response] }
68
+ config.subscribe([modified_filer_key_result]) { |event| }
69
+ end
70
+
71
+ ```
72
+
73
+ You can also reject or accept events by modifying the `.event_filter/1`
74
+
75
+ **Note:** If the filter does not return an event. The `all` listener will not be triggered.
76
+
77
+ ```ruby
78
+ TheCaptain::Event.configure do |config|
79
+ # If the event's decision id is 1000, then ignore it (i.e.: don't return the event)
80
+ config.event_filter = proc { |event| event unless event.descition.id == 1000 }
81
+ end
82
+ ```
83
+
84
+ ## License
85
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TheCaptain
4
+ module Events
5
+ class WebhookController < ActionController::Base
6
+ if ::Rails.application.config.action_controller.default_protect_from_forgery
7
+ skip_before_action :verify_authenticity_token
8
+ end
9
+
10
+ # post
11
+ def event
12
+ ::TheCaptain::Events.instrument(process_event)
13
+ head :ok
14
+ end
15
+
16
+ private
17
+
18
+ def process_event
19
+ request_body = request.body.read
20
+ request_url = request.original_url
21
+ http_version = request.headers["version"] || "HTTP/1.1"
22
+ response = construct_response_from(request_body, request_url, http_version)
23
+ ::TheCaptain::Response::CaptainVessel.new(response)
24
+ end
25
+
26
+ def construct_response_from(payload, uri_destination, http_version)
27
+ HTTP::Response.new(body: payload, uri: uri_destination, status: 200, version: http_version)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ TheCaptain::Events::Engine.routes.draw do
4
+ root to: "webhook#event", via: :post
5
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TheCaptain
4
+ module Events
5
+ class << self
6
+ attr_accessor :adapter, :backend, :namespace, :event_filter, :event_key_filter
7
+
8
+ def configure
9
+ raise ArgumentError, "Must provide a block to configure events" unless block_given?
10
+ yield self
11
+ end
12
+
13
+ def subscribe(kit_name, callable = Proc.new)
14
+ backend.subscribe(namespace.to_regexp(kit_name), adapter.call(callable))
15
+ end
16
+
17
+ def all(callable = Proc.new)
18
+ subscribe(nil, callable)
19
+ end
20
+
21
+ def instrument(event)
22
+ event = event_filter.call(event)
23
+ return unless event
24
+ event_key = event_key_filter.call(event)
25
+ backend.instrument(namespace.call(event_key), event)
26
+ end
27
+
28
+ def listening?(kit_name)
29
+ namespaced_name = namespace.call(kit_name)
30
+ backend.notifier.listening?(namespaced_name)
31
+ end
32
+ end
33
+
34
+ Namespace = Struct.new(:value, :delimiter) do
35
+ def call(name = nil)
36
+ "#{value}#{delimiter}#{name&.to_s&.tr(' ', delimiter)&.downcase}"
37
+ end
38
+
39
+ def to_regexp(name = nil)
40
+ /^#{Regexp.escape(call(name))}/
41
+ end
42
+ end
43
+
44
+ NotificationAdapter = Struct.new(:subscriber) do
45
+ def self.call(callable)
46
+ new(callable)
47
+ end
48
+
49
+ def call(*args)
50
+ payload = args.last
51
+ subscriber.call(payload)
52
+ end
53
+ end
54
+
55
+ self.adapter = NotificationAdapter
56
+ self.backend = ActiveSupport::Notifications
57
+ self.namespace = Namespace.new("captain_event", ".")
58
+ self.event_filter = lambda { |event| event }
59
+ self.event_key_filter = lambda { |event| event.dig(:action) }
60
+ end
61
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/engine"
4
+
5
+ module TheCaptain
6
+ module Events
7
+ class Engine < ::Rails::Engine
8
+ isolate_namespace TheCaptain::Events
9
+
10
+ initializer "the_captain_rails.initialize" do
11
+ require "the_captain_rails"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/notifications"
4
+
5
+ require "the_captain"
6
+ require "the_captain/events"
7
+ require "the_captain/rails/engine" if defined?(Rails)
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: the_captain_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.1.0
5
+ platform: ruby
6
+ authors:
7
+ - George J Protacio-Karaszi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-09-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: the_captain
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '11.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '11.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.5'
69
+ description: The Captain will tell, talk, and taddle on those pesky fraudulent scalliwags.
70
+ email:
71
+ - george@elevatorup.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - README.md
77
+ - app/controllers/the_captain/events/webhook_controller.rb
78
+ - config/routes.rb
79
+ - lib/the_captain/events.rb
80
+ - lib/the_captain/rails/engine.rb
81
+ - lib/the_captain_rails.rb
82
+ homepage: https://github.com/VianetManagement/the-captain-rails
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ - app
91
+ - config
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.7.7
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Ruby on Rails bindings for the The Captain API
108
+ test_files: []