active_webhook 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.env.sample +1 -0
  3. data/.gitignore +63 -0
  4. data/.rspec +4 -0
  5. data/.rubocop.yml +86 -0
  6. data/.todo +48 -0
  7. data/.travis.yml +14 -0
  8. data/CHANGELOG.md +5 -0
  9. data/DEV_README.md +199 -0
  10. data/Gemfile +8 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +483 -0
  13. data/Rakefile +23 -0
  14. data/active_webhook.gemspec +75 -0
  15. data/config/environment.rb +33 -0
  16. data/lib/active_webhook.rb +125 -0
  17. data/lib/active_webhook/adapter.rb +117 -0
  18. data/lib/active_webhook/callbacks.rb +53 -0
  19. data/lib/active_webhook/configuration.rb +105 -0
  20. data/lib/active_webhook/delivery/base_adapter.rb +96 -0
  21. data/lib/active_webhook/delivery/configuration.rb +16 -0
  22. data/lib/active_webhook/delivery/faraday_adapter.rb +19 -0
  23. data/lib/active_webhook/delivery/net_http_adapter.rb +28 -0
  24. data/lib/active_webhook/error_log.rb +7 -0
  25. data/lib/active_webhook/formatting/base_adapter.rb +109 -0
  26. data/lib/active_webhook/formatting/configuration.rb +18 -0
  27. data/lib/active_webhook/formatting/json_adapter.rb +19 -0
  28. data/lib/active_webhook/formatting/url_encoded_adapter.rb +28 -0
  29. data/lib/active_webhook/hook.rb +9 -0
  30. data/lib/active_webhook/logger.rb +21 -0
  31. data/lib/active_webhook/models/configuration.rb +18 -0
  32. data/lib/active_webhook/models/error_log_additions.rb +15 -0
  33. data/lib/active_webhook/models/subscription_additions.rb +72 -0
  34. data/lib/active_webhook/models/topic_additions.rb +70 -0
  35. data/lib/active_webhook/queueing/active_job_adapter.rb +43 -0
  36. data/lib/active_webhook/queueing/base_adapter.rb +67 -0
  37. data/lib/active_webhook/queueing/configuration.rb +15 -0
  38. data/lib/active_webhook/queueing/delayed_job_adapter.rb +28 -0
  39. data/lib/active_webhook/queueing/sidekiq_adapter.rb +43 -0
  40. data/lib/active_webhook/queueing/syncronous_adapter.rb +14 -0
  41. data/lib/active_webhook/subscription.rb +7 -0
  42. data/lib/active_webhook/topic.rb +7 -0
  43. data/lib/active_webhook/verification/base_adapter.rb +31 -0
  44. data/lib/active_webhook/verification/configuration.rb +13 -0
  45. data/lib/active_webhook/verification/hmac_sha256_adapter.rb +20 -0
  46. data/lib/active_webhook/verification/unsigned_adapter.rb +11 -0
  47. data/lib/active_webhook/version.rb +5 -0
  48. data/lib/generators/install_generator.rb +20 -0
  49. data/lib/generators/migrations_generator.rb +24 -0
  50. data/lib/generators/templates/20210618023338_create_active_webhook_tables.rb +31 -0
  51. data/lib/generators/templates/active_webhook_config.rb +87 -0
  52. metadata +447 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bc8acd1e3d7b0ab18220c1550c4036bd52317f4bf8e57d6ff86935703f241e45
4
+ data.tar.gz: aac9a54fced0844aa949f155c6df5fbcc6fe386b9df701e6e1ef9fa1d8b4cf2e
5
+ SHA512:
6
+ metadata.gz: d7c48dbcb856125ee8d951e1ad9998e02048a96aaa452b63a1042b98503d5ed003bdecf6efbd2e7012aeed7deb09c27e5a11d64bd72fb61683c642f6ea5f25b8
7
+ data.tar.gz: ec57e66ad519b0e2a65ed97cd4e750146466a0ffa6ba300826d10c3acf0a55ffb4e49712176d6a9e60afe94b88efc375dacec9444e7de55dec6c7a1fbfc135a8
data/.env.sample ADDED
@@ -0,0 +1 @@
1
+ SIDEKIQ_SOMETHING=1
data/.gitignore ADDED
@@ -0,0 +1,63 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+ *~
13
+ log/*
14
+ measurement/*
15
+
16
+ # Used by dotenv library to load environment variables.
17
+ .env
18
+
19
+
20
+ # Ignore Byebug command history file.
21
+ .byebug_history
22
+
23
+ ## Specific to RubyMotion:
24
+ .dat*
25
+ .repl_history
26
+ build/
27
+ *.bridgesupport
28
+ build-iPhoneOS/
29
+ build-iPhoneSimulator/
30
+
31
+ ## Specific to RubyMotion (use of CocoaPods):
32
+ #
33
+ # We recommend against adding the Pods directory to your .gitignore. However
34
+ # you should judge for yourself, the pros and cons are mentioned at:
35
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
36
+ #
37
+ # vendor/Pods/
38
+
39
+ ## Documentation cache and generated files:
40
+ /.yardoc/
41
+ /_yardoc/
42
+ /doc/
43
+ /rdoc/
44
+
45
+ ## Environment normalization:
46
+ /.bundle/
47
+ /vendor/bundle
48
+ /lib/bundler/man/
49
+
50
+ # for a library or gem, you might want to ignore these files since the code is
51
+ # intended to run in multiple environments; otherwise, check them in:
52
+ Gemfile.lock
53
+
54
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
55
+ .rvmrc
56
+ .ruby-version
57
+ .ruby-gemset
58
+
59
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
60
+ # .rubocop-https?--*
61
+
62
+ # rspec failure tracking
63
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
4
+ --order rand
data/.rubocop.yml ADDED
@@ -0,0 +1,86 @@
1
+ # I can't get the requires to work with sublime:
2
+ # SEE: https://github.com/pderichs/sublime_rubocop/issues/66
3
+ # -- https://gist.github.com/topher6345/4f921ca3e7938132563e
4
+ # -- https://forum.sublimetext.com/t/run-command-after-saving-file/44016
5
+ # -- https://medium.com/devnetwork/running-rubocop-only-on-modified-files-a21aed86e06d
6
+ # -- https://code.tutsplus.com/tutorials/how-to-create-a-sublime-text-2-plugin--net-22685
7
+
8
+ # -- https://github.com/SublimeLinter/SublimeLinter-rubocop/issues/19
9
+ # -- https://github.com/fnando/sublime-codefmt
10
+ # -- https://github.com/fnando/sublime-switch-case
11
+ # -- https://github.com/fnando/sublime-rubocop-completion/issues/1
12
+ # required these fixes:
13
+ # -- install PackageDev https://forum.sublimetext.com/t/pathlib-not-found-in-purchased-version/49978
14
+ # -- download all 3 packages via git clone rather than package manager
15
+ # -- renamed several files and directories to match
16
+ # -- brew update
17
+ # -- brew doctor
18
+ # -- brew install prettier yapf
19
+
20
+ require:
21
+ - rubocop-performance
22
+ - rubocop-rspec
23
+
24
+ AllCops:
25
+ TargetRubyVersion: 2.5
26
+ NewCops: enable
27
+
28
+ Style/Documentation:
29
+ Enabled: false
30
+
31
+ Naming/VariableNumber:
32
+ Enabled: false
33
+
34
+ Metrics/BlockLength:
35
+ Exclude:
36
+ - "**/*.rake"
37
+ - "config/**/*"
38
+ - "Rakefile"
39
+ - "spec/**/*.rb"
40
+ - "*.gemspec"
41
+
42
+ Layout/LineLength:
43
+ Max: 120
44
+
45
+ Style/BlockComments:
46
+ Enabled: false
47
+
48
+ Style/ClassAndModuleChildren:
49
+ Enabled: false
50
+
51
+ Style/RedundantBegin:
52
+ Enabled: false
53
+
54
+ Style/StringLiterals:
55
+ EnforcedStyle: single_quotes
56
+
57
+ Style/StringLiteralsInInterpolation:
58
+ Enabled: true
59
+
60
+ Style/WordArray:
61
+ EnforcedStyle: brackets
62
+
63
+ Metrics/MethodLength:
64
+ Max: 15
65
+
66
+ Style/HashSyntax:
67
+ Enabled: false
68
+
69
+ Style/StringHashKeys:
70
+ Enabled: false
71
+
72
+ Metrics/AbcSize:
73
+ Enabled: false
74
+
75
+ Layout/DotPosition:
76
+ Enabled: false
77
+
78
+ Lint/AmbiguousBlockAssociation:
79
+ Exclude:
80
+ - "spec/**/*"
81
+
82
+ RSpec/NamedSubject:
83
+ Enabled: false
84
+ # Rails:
85
+ # Enabled: true
86
+
data/.todo ADDED
@@ -0,0 +1,48 @@
1
+
2
+
3
+ -------------------------------------------------------------------------------------
4
+
5
+ ...meanwhile, back at planet scope...
6
+
7
+ bundle exec rspec spec/gql/v2/objects/organization_type_spec.rb spec/gql/v2/objects/user_type_spec.rb spec/gql/v2/objects/query_type_spec.rb spec/gql/v2/objects/webhook_* spec/gql/v2/mutations/webhook_subscriptions/* spec/libs/acts_as_webhook_spec.rb spec/gql/*/schema_type_spec.rb
8
+
9
+
10
+ 1. deploy (wait until friday)
11
+ 1. create new repo
12
+ 1. squash
13
+ 1. push
14
+
15
+
16
+ -------------------------------------------------------------------------------------
17
+
18
+ ...meanwhile, back at planet active_webbhook...
19
+
20
+ 1. deploy (wait until friday)
21
+ 1. create new repo
22
+ 1. squash
23
+ 1. push
24
+
25
+ -------------------------------------------------------------------------------------
26
+ # everything below this line is optional
27
+
28
+ 1. add rate limiting
29
+
30
+ 1. update the readme
31
+ - list all config options with brief descriptions (and link to config file for more information)
32
+ - list all gem dependencies for each adapter
33
+ - change customization to separate use cases
34
+
35
+ 1. solve rubygems
36
+
37
+ 1. fix generator
38
+ - didn't work for scope
39
+ - rename active_webhook_config.rb to initializers/active_webhook.rb
40
+ ? add option to install models & factories (see devise) [accept list of models to create & namespace]
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ # SEE: https://docs.travis-ci.com/user/languages/ruby/
2
+
3
+ language: ruby
4
+ rvm:
5
+ - 2.5.3
6
+ before_install:
7
+ - gem install bundler:1.17.3
8
+ install:
9
+ - bundle _1.17.3_ install --jobs=3 --retry=3
10
+ - bundle exec rake db:reset
11
+ env:
12
+ # - 'TEST_RAILS_VERSION="~> 5.2.3"'
13
+ # - 'TEST_RAILS_VERSION="~> 6.0.3"'
14
+ - 'TEST_RAILS_VERSION="~> 6.1.3.2"'
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (02-Jul-2021)
4
+
5
+ * Initial public release
data/DEV_README.md ADDED
@@ -0,0 +1,199 @@
1
+ ## inspired by
2
+
3
+ `https://benediktdeicke.com/2017/09/sending-webhooks-with-rails/`
4
+
5
+ ## look at importing server from https://github.com/nsweeting/activehook
6
+
7
+ ## bootstrapped with:
8
+
9
+ `bundle gem active_webhook --test=rspec --mit`
10
+
11
+ ## bootstrapped dummy rails app with
12
+
13
+ `rails new dummy --skip-spring --skip-listen --skip-bootsnap --skip-action-text --skip-active-storage --skip-action-cable --skip-action-mailer --skip-action-mailbox --skip-test --skip-system-test --skip-active-job --skip-active-record --skip-javascript`
14
+
15
+ [then dicarded and used fully dummy]
16
+
17
+ [SEE](https://lokalise.com/blog/create-a-ruby-gem-basics/)
18
+ [SEE](https://lokalise.com/blog/how-to-create-a-ruby-gem-testing-suite/)
19
+
20
+ rails d model active_webhook/subscription
21
+
22
+ rails d model active_webhook/topic
23
+
24
+ rails g model active_webhook/subscription \
25
+ user_id:integer \
26
+ state:tinyint \
27
+ topic_key:string \
28
+ topic_version:string \
29
+ updated_at:datetime \
30
+ disabled_reason:string \
31
+ format:string \
32
+ callback_url:text \
33
+ company_id:integer \
34
+ query:text
35
+
36
+ rails g model active_webhook/topic \
37
+ key:string \
38
+ version:string \
39
+ state:tinyint \
40
+ query:string \
41
+
42
+
43
+ -------------------------------------------------------------------------------------
44
+ # everything below this line is deferred until needed
45
+
46
+ 1. consolidate formatting/*_adapter.rb into hook/builder.rb
47
+ - change content_type & encoded_data methods use ActiveWebhook.configuration.content_type
48
+ - add ActiveWebhook.configuration.builder
49
+ - delete Hook (in favor of basic hash) ?
50
+
51
+ 1. add `config.queueing.delay` trigger(in: nil) => [1.second]
52
+ - do not add to Topic or Subscription models (because they aren't loaded before check for performance reasons)
53
+ - evaluate to config.nil? ? method.option : config.value
54
+ - configure each queuing adapter to pass delay to underlying implementation
55
+
56
+ 1. add `config.buffering.adapter` => [:disabled, :enabled, Buffering::BaseAdapter]
57
+ - introduce shim into queueing/base_adapter#call that passes to active_webbhook/buffer/*adapter and back
58
+ - make sure that all queuing adapters delay after buffer is flushed
59
+ - add buffer/disabled_adapter and buffer/enabled_adapter
60
+ - implement as follows:
61
+ - if enabled, require `request_store`
62
+ - monkey_patch transaction block (or observe callbacks)
63
+ - add `buffer.t_level` and `buffer.entries`
64
+ - store t_level with buffer entry args
65
+ - on rollback, `buffer.entries.delete` where `entry.t_level` >= `buffer.t_level`; then `buffer.t_level -= 1`
66
+ - on commit, `buffer.entries.t.level -= 1` where `entry.t_level` >= `buffer.t_level`; then `buffer.t_level -= 1`
67
+ - if rails, `ActionController.include ActiveWebhook::Buferable` that wraps each action with `begin; ActiveWebhook.buffer.start; ensure; ActiveWebhook.buffer.flush; end
68
+ - note: Def controller might require different implementation from transactions; need to research transaction callbacks and commits during transaction
69
+ - https://github.com/steveklabnik/request_store
70
+ - https://www.justinweiss.com/articles/better-globals-with-a-tiny-activesupport-module/
71
+
72
+ 1. add `ActiveWebhook.cancel(...same args as trigger)`
73
+ - clears matching `buffer.entries` via `buffer.cancel(**kwargs)`
74
+ - relies on `config.buffer.eq?(a, b)`
75
+
76
+ 1. add `config.buffering.remove_duplicates` and trigger(remove_duplicates: nil, **) [true, false]
77
+ - do not add to Topic or Subscription models (because they aren't loaded before check for performance reasons)
78
+ - evaluate to config.nil? ? method.option : config.value
79
+ - raise runtime error if true and bufferring_adapter is disabled
80
+ - relies on `config.buffer.eq?(a, b)`
81
+
82
+ 1. add `config.delivery.retry_count` and trigger(retry_count: nil, **) [true, false]
83
+ - do not add to Topic or Subscription models (because they aren't loaded before check for performance reasons)
84
+ - evaluate to config.nil? ? method.option : config.value
85
+ - solve how to specify retry count with exponential backoff for each queuing adapter
86
+ - match option name to active_job
87
+
88
+ 1. add `config.delivery.time_limit` and trigger(time_limit: nil, **) [true, false]
89
+ - do not add to Topic or Subscription models (because they aren't loaded before check for performance reasons)
90
+ - evaluate to config.nil? ? method.option : config.value
91
+ - solve how to specify time limit for each queuing adapter
92
+ - match option name to active_job
93
+
94
+ 1. add jid to context in syncronous queuing adapter (if possible)
95
+ - solve how to generate an auto increment Id across servers (maybe hash or hex a server id and counter; could store server in db and load on start)
96
+ - https://www.google.com/search?q=rails+set+global+variable+per+request&client=safari&hl=en-us&ei=xF3NYKDaKYX_-wSAu5KIAw&oq=rails+set+global+variable+per+request
97
+
98
+
99
+
100
+ Scratchpad
101
+ ---
102
+ # in spec/spec_helper.rb
103
+
104
+ # Restablish connection (severed from app load)
105
+ ActiveRecord::Base.establish_connection(DB_CONFIG)
106
+
107
+ # log sql (as level debug)
108
+ ActiveRecord::Base.logger = Rails.logger
109
+
110
+
111
+ ----
112
+ # in Rakefile
113
+
114
+ # require "bundler/gem_tasks"
115
+ # require "rspec/core/rake_task"
116
+ # Bundler::GemHelper.install_tasks
117
+ # rescue LoadError
118
+ # puts "although not required, bundler is recommended for running the tests"
119
+ # end
120
+ # require "rake"
121
+
122
+ # RSpec::Core::RakeTask.new(:spec) do |spec|
123
+ # spec.pattern = 'spec/**/*_spec.rb'
124
+ # end
125
+
126
+ # namespace :db do
127
+ # desc "Create the database"
128
+ # task :create do
129
+ # initialize_rake_environment
130
+ # if ActiveRecord::Base.connection.respond_to? :create_database
131
+ # ActiveRecord::Base.connection.create_database(DB_CONFIG["database"])
132
+ # else
133
+ # ActiveRecord::Base.connection.send :connect
134
+ # end
135
+ # puts "Database created."
136
+ # end
137
+
138
+ # desc "Migrate the database"
139
+ # task :migrate do
140
+ # initialize_rake_environment
141
+ # ActiveRecord::Base.connection.migration_context.migrate
142
+ # Rake::Task["db:schema"].invoke
143
+ # puts "Database migrated."
144
+ # end
145
+
146
+ # desc "Drop the database"
147
+ # task :drop do
148
+ # initialize_rake_environment
149
+ # ActiveRecord::Base.connection.close
150
+ # if ActiveRecord::Base.connection.respond_to? :drop_database
151
+ # ActiveRecord::Base.connection.drop_database(DB_CONFIG["database"])
152
+ # else
153
+ # f = [__dir__, "db", "#{ENV['RACK_ENV']}.sqlite3"].join("/")
154
+ # File.delete(f) if File.exist?(f)
155
+ # end
156
+ # puts "Database deleted."
157
+ # end
158
+
159
+ # desc "Reset the database"
160
+ # task :reset => %i[drop create migrate]
161
+
162
+ # desc "Create a db/schema.rb file that is portable against any DB supported by AR"
163
+ # task :schema do
164
+ # initialize_rake_environment
165
+ # require "active_record/schema_dumper"
166
+ # filename = "db/schema.rb"
167
+ # File.open(filename, "w:utf-8") do |file|
168
+ # ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
169
+ # end
170
+ # end
171
+ # end
172
+
173
+ # namespace :g do
174
+ # desc "Generate migration"
175
+ # task :migration do
176
+ # initialize_rake_environment
177
+ # name = ARGV[1] || raise("Specify name: rake g:migration your_migration")
178
+ # timestamp = Time.now.strftime("%Y%m%d%H%M%S")
179
+ # path = File.expand_path("../db/migrate/#{timestamp}_#{name}.rb", __FILE__)
180
+ # migration_class = name.split("_").map(&:capitalize).join
181
+
182
+ # File.open(path, "w") do |file|
183
+ # file.write <<~FILE
184
+ # class #{migration_class} < ActiveRecord::Migration
185
+ # def self.up
186
+ # end
187
+ # def self.down
188
+ # end
189
+ # end
190
+ # FILE
191
+ # end
192
+
193
+ # puts "Migration #{path} created"
194
+ # abort # needed stop other tasks
195
+ # end
196
+ # end
197
+
198
+
199
+
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in active_webhook.gemspec
8
+ gemspec