fuik 0.11.0 → 0.13.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +162 -25
  3. data/app/assets/images/fuik/icons/46elks.jpg +0 -0
  4. data/app/assets/images/fuik/icons/lettermint.jpg +0 -0
  5. data/app/assets/images/fuik/icons/smtp2go.jpg +0 -0
  6. data/app/assets/javascript/attractivejs-0.12.0.min.js +1 -0
  7. data/app/assets/stylesheets/fuik/application.css +204 -81
  8. data/app/controllers/concerns/fuik/event_type.rb +32 -7
  9. data/app/controllers/fuik/events_controller.rb +7 -2
  10. data/app/controllers/fuik/retries_controller.rb +12 -0
  11. data/app/controllers/fuik/webhooks_controller.rb +29 -8
  12. data/app/jobs/fuik/webhook_processing_job.rb +21 -0
  13. data/app/models/fuik/event.rb +36 -0
  14. data/app/models/fuik/webhook_event/filterable.rb +25 -0
  15. data/app/models/fuik/webhook_event.rb +34 -1
  16. data/app/views/fuik/events/_filters.html.erb +29 -0
  17. data/app/views/fuik/events/index.html.erb +7 -1
  18. data/app/views/fuik/events/show.html.erb +43 -20
  19. data/app/views/layouts/fuik/application.html.erb +12 -2
  20. data/config/routes.rb +4 -1
  21. data/lib/fuik/configuration.rb +29 -0
  22. data/lib/fuik/engine.rb +0 -4
  23. data/lib/fuik/errors.rb +5 -0
  24. data/lib/fuik/notifications.rb +48 -0
  25. data/lib/fuik/routing/provider_constraint.rb +4 -4
  26. data/lib/fuik/test_helpers.rb +33 -0
  27. data/lib/fuik/version.rb +1 -1
  28. data/lib/fuik.rb +9 -0
  29. data/lib/generators/fuik/provider/templates/base.rb.tt +11 -2
  30. data/lib/generators/fuik/provider/templates/github/base.rb.tt +3 -0
  31. data/lib/generators/fuik/provider/templates/lettermint/base.rb.tt +32 -0
  32. data/lib/generators/fuik/provider/templates/lettermint/message_failed.rb.tt +16 -0
  33. data/lib/generators/fuik/provider/templates/lettermint/message_hard_bounced.rb.tt +16 -0
  34. data/lib/generators/fuik/provider/templates/lettermint/message_soft_bounced.rb.tt +16 -0
  35. data/lib/generators/fuik/provider/templates/lettermint/message_suppressed.rb.tt +15 -0
  36. data/lib/generators/fuik/provider/templates/loops/base.rb.tt +2 -0
  37. data/lib/generators/fuik/provider/templates/postmark/base.rb.tt +1 -0
  38. data/lib/generators/fuik/provider/templates/smtp2go/base.rb.tt +4 -0
  39. data/lib/generators/fuik/provider/templates/smtp2go/bounce.rb.tt +16 -0
  40. data/lib/generators/fuik/provider/templates/smtp2go/reject.rb.tt +14 -0
  41. data/lib/generators/fuik/provider/templates/smtp2go/spam.rb.tt +13 -0
  42. data/lib/generators/fuik/provider/templates/smtp2go/unsubscribe.rb.tt +13 -0
  43. data/lib/generators/fuik/provider/templates/spinal/base.rb.tt +16 -0
  44. data/lib/generators/fuik/provider/templates/spinal/collection_synced.rb.tt +14 -0
  45. data/lib/generators/fuik/provider/templates/spinal/resource_created.rb.tt +14 -0
  46. data/lib/generators/fuik/provider/templates/spinal/resource_pushed.rb.tt +13 -0
  47. data/lib/generators/fuik/provider/templates/spinal/resource_scheduled.rb.tt +13 -0
  48. data/lib/generators/fuik/provider/templates/spinal/resource_unscheduled.rb.tt +12 -0
  49. metadata +32 -4
data/lib/fuik.rb CHANGED
@@ -1,7 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "fuik/version"
4
+ require "fuik/errors"
5
+ require "fuik/configuration"
2
6
  require "fuik/dot_access"
7
+ require "fuik/notifications"
3
8
  require "fuik/engine"
4
9
 
5
10
  module Fuik
6
11
  class InvalidSignature < StandardError; end
12
+
13
+ def self.deprecator
14
+ @deprecator ||= ActiveSupport::Deprecation.new("1.0", "Fuik")
15
+ end
7
16
  end
@@ -1,8 +1,17 @@
1
1
  module <%= provider_module_name %>
2
2
  class Base < Fuik::Event
3
3
  # def self.verify!(request)
4
- # TODO: Implement signature verification
5
- # raise Fuik::InvalidSignature # only raise when signature is invalid
4
+ # # TODO: Implement signature verification
5
+ # # raise Fuik::InvalidSignature # only raise when signature is invalid
6
6
  # end
7
+
8
+ # Override if Fuik can't find the event type or id on its own:
9
+ #
10
+ # event_type header: "X-Custom-Event"
11
+ # event_type payload: "event_type"
12
+ # event_type "always_this_value"
13
+ #
14
+ # event_id header: "X-Custom-Id"
15
+ # event_id payload: "id"
7
16
  end
8
17
  end
@@ -1,5 +1,8 @@
1
1
  module <%= provider_module_name %>
2
2
  class Base < Fuik::Event
3
+ event_type header: "X-Github-Event"
4
+ event_id header: "X-GitHub-Delivery"
5
+
3
6
  def self.verify!(request)
4
7
  secret = Rails.application.credentials.dig(:github, :secret)
5
8
  signature = request.headers["X-Hub-Signature-256"]
@@ -0,0 +1,32 @@
1
+ module <%= provider_module_name %>
2
+ class Base < Fuik::Event
3
+ def self.verify!(request)
4
+ secret = Rails.application.credentials.dig(:lettermint, :signing_secret)
5
+ signature_header = request.headers["X-Lettermint-Signature"] || ""
6
+
7
+ elements = {}
8
+ signature_header.split(",").each do |element|
9
+ key, value = element.split("=", 2)
10
+
11
+ elements[key] = value if key && value
12
+ end
13
+
14
+ timestamp = elements["t"]
15
+ signature = elements["v1"]
16
+
17
+ raise Fuik::InvalidSignature if timestamp.blank? || signature.blank?
18
+
19
+ now = Time.current.to_i
20
+ raise Fuik::InvalidSignature if (now - timestamp.to_i).abs > TOLERANCE
21
+
22
+ signed_payload = "#{timestamp}.#{request.raw_post}"
23
+ expected = OpenSSL::HMAC.hexdigest("SHA256", secret, signed_payload)
24
+
25
+ raise Fuik::InvalidSignature unless ActiveSupport::SecurityUtils.secure_compare(expected, signature)
26
+ end
27
+
28
+ private
29
+
30
+ TOLERANCE = 5.minutes
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ module <%= provider_module_name %>
2
+ class MessageFailed < Base
3
+ def process!
4
+ # payload.data.recipient # email address that failed
5
+ # payload.data.reason # failure reason (e.g., "A network error occurred.")
6
+ # payload.data.response.status_code # SMTP status code
7
+ # payload.data.subject # email subject
8
+ # payload.data.message_id # message UUID
9
+ # payload.data.tag # message tag (or nil)
10
+
11
+ # TODO: Add business logic
12
+
13
+ @webhook_event.processed!
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module <%= provider_module_name %>
2
+ class MessageHardBounced < Base
3
+ def process!
4
+ # payload.data.recipient # email address that hard bounced
5
+ # payload.data.response.enhanced_status_code # SMTP enhanced status code (e.g., "5.1.1")
6
+ # payload.data.response.content # SMTP response text (e.g., "User unknown")
7
+ # payload.data.subject # email subject
8
+ # payload.data.message_id # message UUID
9
+ # payload.data.tag # message tag (or nil)
10
+
11
+ # TODO: Add business logic
12
+
13
+ @webhook_event.processed!
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module <%= provider_module_name %>
2
+ class MessageSoftBounced < Base
3
+ def process!
4
+ # payload.data.recipient # email address that soft bounced
5
+ # payload.data.response.enhanced_status_code # SMTP enhanced status code (e.g., "4.2.2")
6
+ # payload.data.response.content # SMTP response text (e.g., "Mailbox full")
7
+ # payload.data.subject # email subject
8
+ # payload.data.message_id # message UUID
9
+ # payload.data.tag # message tag (or nil)
10
+
11
+ # TODO: Add business logic
12
+
13
+ @webhook_event.processed!
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module <%= provider_module_name %>
2
+ class MessageSuppressed < Base
3
+ def process!
4
+ # payload.data.recipient # email address that was suppressed
5
+ # payload.data.reason # suppression reason (e.g., "hard_bounce", "spam_complaint")
6
+ # payload.data.subject # email subject
7
+ # payload.data.message_id # message UUID
8
+ # payload.data.tag # message tag (or nil)
9
+
10
+ # TODO: Add business logic
11
+
12
+ @webhook_event.processed!
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,7 @@
1
1
  module <%= provider_module_name %>
2
2
  class Base < Fuik::Event
3
+ event_id header: "webhook-id"
4
+
3
5
  def self.verify!(request)
4
6
  secret = Rails.application.credentials.dig(:loops, :signing_secret)
5
7
  secret_bytes = Base64.strict_decode64(secret.split("_")[1])
@@ -1,4 +1,5 @@
1
1
  module <%= provider_module_name %>
2
2
  class Base < Fuik::Event
3
+ event_type header: "X-Postmark-Event"
3
4
  end
4
5
  end
@@ -0,0 +1,4 @@
1
+ module <%= provider_module_name %>
2
+ class Base < Fuik::Event
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ module <%= provider_module_name %>
2
+ class Bounce < Base
3
+ def process!
4
+ # payload.rcpt # email address that bounced
5
+ # payload.bounce # "hard" or "soft"
6
+ # payload.host # recipient server
7
+ # payload.message # SMTP error message
8
+ # payload.subject # email subject
9
+ # payload.email_id # email identifier
10
+
11
+ # TODO: Add business logic
12
+
13
+ @webhook_event.processed!
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ module <%= provider_module_name %>
2
+ class Reject < Base
3
+ def process!
4
+ # payload.rcpt # email address that was rejected
5
+ # payload.message # rejection reason
6
+ # payload.subject # email subject
7
+ # payload.email_id # email identifier
8
+
9
+ # TODO: Add business logic
10
+
11
+ @webhook_event.processed!
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module <%= provider_module_name %>
2
+ class Spam < Base
3
+ def process!
4
+ # payload.rcpt # email address that complained
5
+ # payload.subject # email subject
6
+ # payload.email_id # email identifier
7
+
8
+ # TODO: Add business logic
9
+
10
+ @webhook_event.processed!
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module <%= provider_module_name %>
2
+ class Unsubscribe < Base
3
+ def process!
4
+ # payload.rcpt # email address that unsubscribed
5
+ # payload.subject # email subject
6
+ # payload.email_id # email identifier
7
+
8
+ # TODO: Add business logic
9
+
10
+ @webhook_event.processed!
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module <%= provider_module_name %>
2
+ class Base < Fuik::Event
3
+ event_type payload: "type"
4
+ event_id payload: "data.id"
5
+
6
+ # def self.verify!(request)
7
+ # secret = Rails.application.credentials.dig(:spinal, :webhook_secret)
8
+ # signature = request.headers["webhook-signature"]
9
+ # id = request.headers["webhook-id"]
10
+ # timestamp = request.headers["webhook-timestamp"]
11
+
12
+ # expected = OpenSSL::HMAC.base64digest("SHA256", secret, "#{id}.#{timestamp}.#{request.raw_post}")
13
+ # raise Fuik::InvalidSignature unless Rack::Utils.secure_compare(signature, "v1,#{expected}")
14
+ # end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ module <%= provider_module_name %>
2
+ class CollectionSynced < Base
3
+ def process!
4
+ # payload["data"]["id"] # collection id
5
+ # payload["data"]["stats"]["added"] # resources added during sync
6
+ # payload["data"]["stats"]["updated"] # resources updated during sync
7
+ # payload["data"]["stats"]["removed"] # resources removed during sync
8
+
9
+ # TODO: Add business logic
10
+
11
+ @webhook_event.processed!
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module <%= provider_module_name %>
2
+ class ResourceCreated < Base
3
+ def process!
4
+ # payload["data"]["id"] # resource id
5
+ # payload["data"]["filename"] # e.g., "posts/hello-world.md"
6
+ # payload["data"]["relative_path"] # e.g., "posts/hello-world"
7
+ # payload["data"]["status"] # "draft" | "published"
8
+
9
+ # TODO: Add business logic
10
+
11
+ @webhook_event.processed!
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module <%= provider_module_name %>
2
+ class ResourcePushed < Base
3
+ def process!
4
+ # payload["data"]["id"] # resource id
5
+ # payload["data"]["filename"] # e.g., "posts/hello-world.md"
6
+ # payload["data"]["status"] # "draft" | "published"
7
+
8
+ # TODO: Add business logic
9
+
10
+ @webhook_event.processed!
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module <%= provider_module_name %>
2
+ class ResourceScheduled < Base
3
+ def process!
4
+ # payload["data"]["id"] # resource id
5
+ # payload["data"]["filename"] # e.g., "posts/hello-world.md"
6
+ # payload["data"]["published_at"] # ISO8601 scheduled publish time
7
+
8
+ # TODO: Add business logic
9
+
10
+ @webhook_event.processed!
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module <%= provider_module_name %>
2
+ class ResourceUnscheduled < Base
3
+ def process!
4
+ # payload["data"]["id"] # resource id
5
+ # payload["data"]["filename"] # e.g., "posts/hello-world.md"
6
+
7
+ # TODO: Add business logic
8
+
9
+ @webhook_event.processed!
10
+ end
11
+ end
12
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fuik
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rails Designer
@@ -35,6 +35,7 @@ files:
35
35
  - MIT-LICENSE
36
36
  - README.md
37
37
  - Rakefile
38
+ - app/assets/images/fuik/icons/46elks.jpg
38
39
  - app/assets/images/fuik/icons/adyen.jpg
39
40
  - app/assets/images/fuik/icons/anthropic.jpg
40
41
  - app/assets/images/fuik/icons/apple.jpg
@@ -47,6 +48,7 @@ files:
47
48
  - app/assets/images/fuik/icons/gitlab.jpg
48
49
  - app/assets/images/fuik/icons/google.jpg
49
50
  - app/assets/images/fuik/icons/gumroad.jpg
51
+ - app/assets/images/fuik/icons/lettermint.jpg
50
52
  - app/assets/images/fuik/icons/linkedin.jpg
51
53
  - app/assets/images/fuik/icons/loops.jpg
52
54
  - app/assets/images/fuik/icons/mailgun.jpg
@@ -58,34 +60,44 @@ files:
58
60
  - app/assets/images/fuik/icons/resend.jpg
59
61
  - app/assets/images/fuik/icons/shopify.jpg
60
62
  - app/assets/images/fuik/icons/slack.jpg
63
+ - app/assets/images/fuik/icons/smtp2go.jpg
61
64
  - app/assets/images/fuik/icons/stripe.jpg
62
65
  - app/assets/images/fuik/icons/telegram.jpg
63
66
  - app/assets/images/fuik/icons/twitter.jpg
64
67
  - app/assets/images/fuik/icons/userlist.jpg
65
68
  - app/assets/images/fuik/icons/webhook.svg
66
69
  - app/assets/images/fuik/icons/zoom.jpg
70
+ - app/assets/javascript/attractivejs-0.12.0.min.js
67
71
  - app/assets/stylesheets/fuik/application.css
68
72
  - app/controllers/concerns/fuik/event_type.rb
69
73
  - app/controllers/fuik/application_controller.rb
70
74
  - app/controllers/fuik/downloads_controller.rb
71
75
  - app/controllers/fuik/events_controller.rb
76
+ - app/controllers/fuik/retries_controller.rb
72
77
  - app/controllers/fuik/webhooks_controller.rb
73
78
  - app/helpers/fuik/highlight_helper.rb
74
79
  - app/helpers/fuik/icon_helper.rb
75
80
  - app/jobs/fuik/application_job.rb
81
+ - app/jobs/fuik/webhook_processing_job.rb
76
82
  - app/models/fuik/application_record.rb
77
83
  - app/models/fuik/event.rb
78
84
  - app/models/fuik/webhook_event.rb
85
+ - app/models/fuik/webhook_event/filterable.rb
79
86
  - app/views/fuik/events/_copy_button.html.erb
87
+ - app/views/fuik/events/_filters.html.erb
80
88
  - app/views/fuik/events/index.html.erb
81
89
  - app/views/fuik/events/show.html.erb
82
90
  - app/views/layouts/fuik/application.html.erb
83
91
  - config/routes.rb
84
92
  - db/migrate/20250101000000_create_webhook_events.rb
85
93
  - lib/fuik.rb
94
+ - lib/fuik/configuration.rb
86
95
  - lib/fuik/dot_access.rb
87
96
  - lib/fuik/engine.rb
97
+ - lib/fuik/errors.rb
98
+ - lib/fuik/notifications.rb
88
99
  - lib/fuik/routing/provider_constraint.rb
100
+ - lib/fuik/test_helpers.rb
89
101
  - lib/fuik/version.rb
90
102
  - lib/generators/fuik/install/install_generator.rb
91
103
  - lib/generators/fuik/provider/provider_generator.rb
@@ -96,6 +108,11 @@ files:
96
108
  - lib/generators/fuik/provider/templates/github/installation_created.rb.tt
97
109
  - lib/generators/fuik/provider/templates/github/push.rb.tt
98
110
  - lib/generators/fuik/provider/templates/github/star_created.rb.tt
111
+ - lib/generators/fuik/provider/templates/lettermint/base.rb.tt
112
+ - lib/generators/fuik/provider/templates/lettermint/message_failed.rb.tt
113
+ - lib/generators/fuik/provider/templates/lettermint/message_hard_bounced.rb.tt
114
+ - lib/generators/fuik/provider/templates/lettermint/message_soft_bounced.rb.tt
115
+ - lib/generators/fuik/provider/templates/lettermint/message_suppressed.rb.tt
99
116
  - lib/generators/fuik/provider/templates/loops/base.rb.tt
100
117
  - lib/generators/fuik/provider/templates/loops/contact_unsubscribed.rb.tt
101
118
  - lib/generators/fuik/provider/templates/loops/email_hard_bounced.rb.tt
@@ -110,6 +127,17 @@ files:
110
127
  - lib/generators/fuik/provider/templates/resend/base.rb.tt
111
128
  - lib/generators/fuik/provider/templates/resend/email_bounced.rb.tt
112
129
  - lib/generators/fuik/provider/templates/resend/email_complained.rb.tt
130
+ - lib/generators/fuik/provider/templates/smtp2go/base.rb.tt
131
+ - lib/generators/fuik/provider/templates/smtp2go/bounce.rb.tt
132
+ - lib/generators/fuik/provider/templates/smtp2go/reject.rb.tt
133
+ - lib/generators/fuik/provider/templates/smtp2go/spam.rb.tt
134
+ - lib/generators/fuik/provider/templates/smtp2go/unsubscribe.rb.tt
135
+ - lib/generators/fuik/provider/templates/spinal/base.rb.tt
136
+ - lib/generators/fuik/provider/templates/spinal/collection_synced.rb.tt
137
+ - lib/generators/fuik/provider/templates/spinal/resource_created.rb.tt
138
+ - lib/generators/fuik/provider/templates/spinal/resource_pushed.rb.tt
139
+ - lib/generators/fuik/provider/templates/spinal/resource_scheduled.rb.tt
140
+ - lib/generators/fuik/provider/templates/spinal/resource_unscheduled.rb.tt
113
141
  - lib/generators/fuik/provider/templates/stripe/base.rb.tt
114
142
  - lib/generators/fuik/provider/templates/stripe/checkout_session_completed.rb.tt
115
143
  - lib/generators/fuik/provider/templates/stripe/customer_subscription_deleted.rb.tt
@@ -117,11 +145,11 @@ files:
117
145
  - lib/generators/fuik/provider/templates/stripe/payment_intent_succeeded.rb.tt
118
146
  - lib/generators/fuik/provider/templates/userlist/base.rb.tt
119
147
  - lib/generators/fuik/provider/templates/userlist/user_unsubscribed.rb.tt
120
- homepage: https://railsdesigner.com/fuik/
148
+ homepage: https://railsdesigner.com/open-source/fuik/
121
149
  licenses:
122
150
  - MIT
123
151
  metadata:
124
- homepage_uri: https://railsdesigner.com/fuik/
152
+ homepage_uri: https://railsdesigner.com/open-source/fuik/
125
153
  source_code_uri: https://github.com/Rails-Designer/fuik/
126
154
  rdoc_options: []
127
155
  require_paths:
@@ -137,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
165
  - !ruby/object:Gem::Version
138
166
  version: '0'
139
167
  requirements: []
140
- rubygems_version: 4.0.9
168
+ rubygems_version: 4.0.14
141
169
  specification_version: 4
142
170
  summary: A fish trap for webhooks
143
171
  test_files: []