fuik 0.5.0 → 0.7.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.
- checksums.yaml +4 -4
- data/README.md +7 -3
- data/app/assets/stylesheets/fuik/application.css +38 -6
- data/app/controllers/fuik/webhooks_controller.rb +1 -1
- data/app/views/fuik/events/_copy_button.html.erb +6 -0
- data/app/views/fuik/events/show.html.erb +3 -3
- data/app/views/layouts/fuik/application.html.erb +4 -3
- data/lib/fuik/version.rb +1 -1
- data/lib/generators/fuik/install/install_generator.rb +0 -4
- data/lib/generators/fuik/provider/provider_generator.rb +14 -2
- data/lib/generators/fuik/provider/templates/github/base.rb.tt +1 -1
- data/lib/generators/fuik/provider/templates/mailpace/base.rb.tt +1 -1
- data/lib/generators/fuik/provider/templates/stripe/base.rb.tt +1 -1
- data/lib/generators/fuik/provider/templates/stripe/checkout_session_completed.rb.tt +6 -4
- data/lib/generators/fuik/provider/templates/stripe/customer_subscription_deleted.rb.tt +2 -2
- data/lib/generators/fuik/provider/templates/stripe/customer_subscription_updated.rb.tt +6 -4
- data/lib/generators/fuik/provider/templates/stripe/payment_intent_succeeded.rb.tt +13 -0
- metadata +8 -5
- data/lib/generators/fuik/install/templates/README +0 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5c68174e847f42afee9dab0fd8777877a9b53d6166942e493b069006eddd44af
|
|
4
|
+
data.tar.gz: 68bb2bec0d47a7f347150ecca7330b63dd304fda52d14fca1250d7279fd56978
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 128b403d2748c3bf8fb268d980a946335ad98043a70c38022b717f4d367ac09c88a93984a12802400443ba2634c2f3a6a869da3f00741d61b930f25343d84f2a
|
|
7
|
+
data.tar.gz: '0809ff55133946fcc8c0e80849a9ad77c0e36c3c9ee951cd1b58a6e7be5b90ed67c5d3c7819c127f8be977b26c2e4c926e3b5a053cddd1c1638cbe063d3b6423'
|
data/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
Fuik (Dutch for fish trap) is a Rails engine that catches and stores webhooks from any provider. View all events in the admin interface, then create event classes to add your business logic.
|
|
6
6
|
|
|
7
|
+
<img alt="Fuik admin interface" src="https://raw.githubusercontent.com/Rails-Designer/fuik/HEAD/.github/docs/webhooks-index.jpg" style="max-width: 100%;">
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
**Sponsored By [Rails Designer](https://railsdesigner.com/)**
|
|
9
11
|
|
|
@@ -54,7 +56,9 @@ The engine mounts at `/webhooks` automatically.
|
|
|
54
56
|
|
|
55
57
|
Visit `/webhooks` to see all received webhooks. Click any event to see the full payload, headers and status.
|
|
56
58
|
|
|
57
|
-
<img alt="Fuik
|
|
59
|
+
<img alt="Fuik event detail interface" src="https://raw.githubusercontent.com/Rails-Designer/fuik/HEAD/.github/docs/event-detail.jpg" style="max-width: 100%;">
|
|
60
|
+
|
|
61
|
+
⚠️ The `/webhooks` path is by default not protected. Easiest is to set `Fuik::Engine.config.events_controller_parent` to a controller that requires authentication.
|
|
58
62
|
|
|
59
63
|
|
|
60
64
|
### Add business logic
|
|
@@ -112,7 +116,7 @@ If `Provider::Base.verify!` exists, Fuik calls it automatically. Invalid signatu
|
|
|
112
116
|
|
|
113
117
|
### Pre-packaged providers
|
|
114
118
|
|
|
115
|
-
Fuik includes ready-to-use [templates for common providers](https://github.com/Rails-
|
|
119
|
+
Fuik includes ready-to-use [templates for common providers](https://github.com/Rails-Designer/fuik/tree/main/lib/generators/fuik/provider/templates).
|
|
116
120
|
|
|
117
121
|
|
|
118
122
|
### Event type & ID lookup
|
|
@@ -148,7 +152,7 @@ event_id:
|
|
|
148
152
|
|
|
149
153
|
## Add your custom provider
|
|
150
154
|
|
|
151
|
-
Have a provider template others could use? Add it to [lib/generators/fuik/provider/templates/your_provider/](https://github.com/Rails-
|
|
155
|
+
Have a provider template others could use? Add it to [lib/generators/fuik/provider/templates/your_provider/](https://github.com/Rails-Designer/fuik/tree/main/lib/generators/fuik/provider/templates) and submit a PR!
|
|
152
156
|
|
|
153
157
|
Include:
|
|
154
158
|
- `base.rb.tt` with signature verification (if applicable);
|
|
@@ -8,18 +8,20 @@
|
|
|
8
8
|
--color-bg-hover: oklch(97% 0.01 250);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
* { box-sizing: border-box; }
|
|
11
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
12
12
|
|
|
13
13
|
body {
|
|
14
|
-
margin: 0;
|
|
15
|
-
padding: 2rem;
|
|
16
|
-
max-inline-size: 80rem;
|
|
17
|
-
margin-inline: auto;
|
|
18
14
|
font-family: system-ui, -apple-system, sans-serif;
|
|
19
15
|
line-height: 1.5;
|
|
20
16
|
color: var(--color-text);
|
|
21
17
|
}
|
|
22
18
|
|
|
19
|
+
main {
|
|
20
|
+
padding: 2rem;
|
|
21
|
+
max-inline-size: 80rem;
|
|
22
|
+
margin-inline: auto;
|
|
23
|
+
}
|
|
24
|
+
|
|
23
25
|
h1 {
|
|
24
26
|
margin-block-end: 1rem;
|
|
25
27
|
font-size: 1.875rem;
|
|
@@ -49,19 +51,49 @@
|
|
|
49
51
|
background: var(--color-bg-hover);
|
|
50
52
|
border-radius: .5rem;
|
|
51
53
|
overflow-x: auto;
|
|
54
|
+
}
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
dl {
|
|
55
58
|
display: grid;
|
|
56
59
|
grid-template-columns: auto 1fr;
|
|
57
60
|
gap: 1rem 2rem;
|
|
61
|
+
overflow: hidden;
|
|
58
62
|
|
|
59
63
|
dt {
|
|
60
64
|
font-weight: 600;
|
|
61
65
|
color: var(--color-text);
|
|
62
66
|
}
|
|
63
67
|
|
|
64
|
-
dd {
|
|
68
|
+
dd {
|
|
69
|
+
position: relative;
|
|
70
|
+
overflow-x: auto;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.copy-button {
|
|
75
|
+
padding: .125rem;
|
|
76
|
+
color: oklch(from var(--color-text) l c h / 80%);
|
|
77
|
+
background: var(--color-bg);
|
|
78
|
+
border: 0;
|
|
79
|
+
border-radius: .25rem;
|
|
80
|
+
cursor: pointer;
|
|
81
|
+
|
|
82
|
+
&:hover {
|
|
83
|
+
color: oklch(from var(--color-text) l c h);
|
|
84
|
+
transition: transform ease-in-out 300ms;
|
|
85
|
+
transform: scale(1.10);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&[position="fixed"] {
|
|
89
|
+
position: absolute;
|
|
90
|
+
top: .5rem; right: .5rem;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
svg {
|
|
94
|
+
width: 1rem;
|
|
95
|
+
aspect-ratio: 1 / 1;
|
|
96
|
+
}
|
|
65
97
|
}
|
|
66
98
|
}
|
|
67
99
|
|
|
@@ -59,7 +59,7 @@ module Fuik
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def event_class_for(provider, event_type)
|
|
62
|
-
"#{provider.camelize}::#{event_type.tr("./:-", "_").camelize}".safe_constantize
|
|
62
|
+
"#{provider.camelize}::#{event_type.tr("./:-[]", "_").camelize}".safe_constantize
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def should_verify? = base_class&.respond_to?(:verify!)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<%# locals: (target:, delay: 5000, position: :relative) %>
|
|
2
|
+
<button data-action="copy" data-target="<%= target %>" data-copy-delay="<%= delay %>" position="<%= position %>" class="copy-button">
|
|
3
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon" stroke-width="">
|
|
4
|
+
<path fill-rule="evenodd" d="M13.887 3.182c.396.037.79.08 1.183.128C16.194 3.45 17 4.414 17 5.517V16.75A2.25 2.25 0 0 1 14.75 19h-9.5A2.25 2.25 0 0 1 3 16.75V5.517c0-1.103.806-2.068 1.93-2.207.393-.048.787-.09 1.183-.128A3.001 3.001 0 0 1 9 1h2c1.373 0 2.531.923 2.887 2.182ZM7.5 4A1.5 1.5 0 0 1 9 2.5h2A1.5 1.5 0 0 1 12.5 4v.5h-5V4Z" clip-rule="evenodd" ></path>
|
|
5
|
+
</svg>
|
|
6
|
+
</button>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<dd><%= @webhook_event.provider %></dd>
|
|
8
8
|
|
|
9
9
|
<dt>Event ID</dt>
|
|
10
|
-
<dd><%= @webhook_event.event_id %></dd>
|
|
10
|
+
<dd><%= tag.code @webhook_event.event_id, id: "event_id" %> <%= render "copy_button", target: "#event_id" %></dd>
|
|
11
11
|
|
|
12
12
|
<dt>Type</dt>
|
|
13
13
|
<dd><%= @webhook_event.event_type %></dd>
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
<dd><%= @webhook_event.created_at.strftime("%Y-%m-%d %H:%M:%S") %></dd>
|
|
20
20
|
|
|
21
21
|
<dt>Payload</dt>
|
|
22
|
-
<dd><pre><%= JSON.pretty_generate(@webhook_event.payload) %></pre
|
|
22
|
+
<dd><pre id="payload"><%= JSON.pretty_generate(@webhook_event.payload) %></pre> <%= render "copy_button", target: "#payload", position: :fixed %></dd>
|
|
23
23
|
|
|
24
24
|
<dt>Headers</dt>
|
|
25
|
-
<dd><pre><%= JSON.pretty_generate(@webhook_event.headers) %></pre
|
|
25
|
+
<dd><pre id="headers"><%= JSON.pretty_generate(@webhook_event.headers) %></pre> <%= render "copy_button", target: "#headers", position: :fixed %></dd>
|
|
26
26
|
|
|
27
27
|
<% if @webhook_event.error.present? %>
|
|
28
28
|
<dt>Error</dt>
|
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
<%= yield :head %>
|
|
9
9
|
|
|
10
10
|
<%= stylesheet_link_tag "fuik/application", media: "all" %>
|
|
11
|
+
<script defer src="https://cdn.jsdelivr.net/npm/attractivejs@0.11.0"></script>
|
|
11
12
|
</head>
|
|
12
13
|
<body>
|
|
13
|
-
|
|
14
|
-
<%= yield %>
|
|
15
|
-
|
|
14
|
+
<main>
|
|
15
|
+
<%= yield %>
|
|
16
|
+
</main>
|
|
16
17
|
</body>
|
|
17
18
|
</html>
|
data/lib/fuik/version.rb
CHANGED
|
@@ -9,7 +9,11 @@ module Fuik
|
|
|
9
9
|
argument :event_names, type: :array, default: []
|
|
10
10
|
|
|
11
11
|
def create_base_class
|
|
12
|
-
|
|
12
|
+
if packaged_base_exists?
|
|
13
|
+
template packaged_base_template_path, "app/webhooks/#{file_name}/base.rb"
|
|
14
|
+
else
|
|
15
|
+
template "base.rb.tt", "app/webhooks/#{file_name}/base.rb"
|
|
16
|
+
end
|
|
13
17
|
end
|
|
14
18
|
|
|
15
19
|
def create_event_classes
|
|
@@ -26,6 +30,14 @@ module Fuik
|
|
|
26
30
|
|
|
27
31
|
private
|
|
28
32
|
|
|
33
|
+
def packaged_base_exists?
|
|
34
|
+
File.exist?(packaged_base_template_path)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def packaged_base_template_path
|
|
38
|
+
File.join(self.class.source_root, file_name, "base.rb.tt")
|
|
39
|
+
end
|
|
40
|
+
|
|
29
41
|
def packaged_event_exists? = File.exist?(packaged_event_template_path)
|
|
30
42
|
|
|
31
43
|
def copy_packaged_event
|
|
@@ -38,7 +50,7 @@ module Fuik
|
|
|
38
50
|
|
|
39
51
|
def packaged_event_template_path = File.join(self.class.source_root, "providers", file_name, "#{event_file_name}.rb.tt")
|
|
40
52
|
|
|
41
|
-
def event_file_path = Rails.join("app", "webhooks", file_name, "#{event_file_name}.rb")
|
|
53
|
+
def event_file_path = Rails.root.join("app", "webhooks", file_name, "#{event_file_name}.rb")
|
|
42
54
|
|
|
43
55
|
def event_file_name = @event_name.underscore
|
|
44
56
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module <%= provider_module_name %>
|
|
2
2
|
class Base < Fuik::Event
|
|
3
3
|
def self.verify!(request)
|
|
4
|
-
secret = Rails.application.credentials.dig(:
|
|
4
|
+
secret = Rails.application.credentials.dig(:github, :secret)
|
|
5
5
|
signature = request.headers["X-Hub-Signature-256"]
|
|
6
6
|
expected_signature = "sha256=" + OpenSSL::HMAC.hexdigest("SHA256", secret, request.raw_post)
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module <%= provider_module_name %>
|
|
2
2
|
class Base < Fuik::Event
|
|
3
3
|
def self.verify!(request)
|
|
4
|
-
public_key_base64 = Rails.application.credentials.dig(:
|
|
4
|
+
public_key_base64 = Rails.application.credentials.dig(:mailpace, :public_key)
|
|
5
5
|
signature_base64 = request.headers["X-MailPace-Signature"]
|
|
6
6
|
|
|
7
7
|
verify_key = Ed25519::VerifyKey.new(Base64.strict_decode64(public_key_base64))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module <%= provider_module_name %>
|
|
2
2
|
class Base < Fuik::Event
|
|
3
3
|
def self.verify!(request)
|
|
4
|
-
secret = Rails.application.credentials.dig(:
|
|
4
|
+
secret = Rails.application.credentials.dig(:stripe, :signing_secret)
|
|
5
5
|
signature = request.headers["Stripe-Signature"]
|
|
6
6
|
|
|
7
7
|
Stripe::Webhook.construct_event(
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
module
|
|
2
|
-
class
|
|
1
|
+
module Stripe
|
|
2
|
+
class CheckoutSessionCompleted < Base
|
|
3
3
|
def process!
|
|
4
|
-
session_id = payload.dig("data", "object", "id")
|
|
5
|
-
|
|
6
4
|
# TODO: Add business logic
|
|
7
5
|
# session = Stripe::Checkout::Session.retrieve(session_id) # this assumes the Stripe gem is available
|
|
8
6
|
|
|
9
7
|
@webhook_event.processed!
|
|
10
8
|
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def session_id = payload.dig("data", "object", "id")
|
|
11
13
|
end
|
|
12
14
|
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
module
|
|
2
|
-
class
|
|
1
|
+
module Stripe
|
|
2
|
+
class CustomerSubscriptionUpdated < Base
|
|
3
3
|
def process!
|
|
4
|
-
subscription_id = payload.dig("data", "object", "id")
|
|
5
|
-
|
|
6
4
|
# TODO: Add business logic
|
|
7
5
|
|
|
8
6
|
@webhook_event.processed!
|
|
9
7
|
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def subscription_id = payload.dig("data", "object", "id")
|
|
10
12
|
end
|
|
11
13
|
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.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rails Designer
|
|
@@ -23,7 +23,9 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: 7.0.0
|
|
26
|
-
description:
|
|
26
|
+
description: Fuik (Dutch for fish trap) is a Rails engine that catches and stores
|
|
27
|
+
webhooks from any provider. View all events in the admin interface, then create
|
|
28
|
+
event classes to add your business logic.
|
|
27
29
|
email:
|
|
28
30
|
- devs@railsdesigner.com
|
|
29
31
|
executables: []
|
|
@@ -42,6 +44,7 @@ files:
|
|
|
42
44
|
- app/models/fuik/application_record.rb
|
|
43
45
|
- app/models/fuik/event.rb
|
|
44
46
|
- app/models/fuik/webhook_event.rb
|
|
47
|
+
- app/views/fuik/events/_copy_button.html.erb
|
|
45
48
|
- app/views/fuik/events/index.html.erb
|
|
46
49
|
- app/views/fuik/events/show.html.erb
|
|
47
50
|
- app/views/layouts/fuik/application.html.erb
|
|
@@ -51,7 +54,6 @@ files:
|
|
|
51
54
|
- lib/fuik/engine.rb
|
|
52
55
|
- lib/fuik/version.rb
|
|
53
56
|
- lib/generators/fuik/install/install_generator.rb
|
|
54
|
-
- lib/generators/fuik/install/templates/README
|
|
55
57
|
- lib/generators/fuik/provider/provider_generator.rb
|
|
56
58
|
- lib/generators/fuik/provider/templates/README
|
|
57
59
|
- lib/generators/fuik/provider/templates/base.rb.tt
|
|
@@ -67,6 +69,7 @@ files:
|
|
|
67
69
|
- lib/generators/fuik/provider/templates/stripe/checkout_session_completed.rb.tt
|
|
68
70
|
- lib/generators/fuik/provider/templates/stripe/customer_subscription_deleted.rb.tt
|
|
69
71
|
- lib/generators/fuik/provider/templates/stripe/customer_subscription_updated.rb.tt
|
|
72
|
+
- lib/generators/fuik/provider/templates/stripe/payment_intent_succeeded.rb.tt
|
|
70
73
|
homepage: https://railsdesigner.com/fuik/
|
|
71
74
|
licenses:
|
|
72
75
|
- MIT
|
|
@@ -87,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
87
90
|
- !ruby/object:Gem::Version
|
|
88
91
|
version: '0'
|
|
89
92
|
requirements: []
|
|
90
|
-
rubygems_version: 4.0.
|
|
93
|
+
rubygems_version: 4.0.4
|
|
91
94
|
specification_version: 4
|
|
92
|
-
summary:
|
|
95
|
+
summary: A fish trap for webhooks
|
|
93
96
|
test_files: []
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
===============================================================================
|
|
2
|
-
|
|
3
|
-
Fuik has been installed! 🎣
|
|
4
|
-
|
|
5
|
-
Next steps:
|
|
6
|
-
|
|
7
|
-
1. Run migrations:
|
|
8
|
-
rails db:migrate
|
|
9
|
-
|
|
10
|
-
2. Webhooks can be sent to:
|
|
11
|
-
POST /webhooks/:provider
|
|
12
|
-
|
|
13
|
-
Example: POST /webhooks/stripe
|
|
14
|
-
|
|
15
|
-
3. (Optional) Generate webhook class for a provider:
|
|
16
|
-
rails generate fuik:provider stripe checkout_session_completed
|
|
17
|
-
|
|
18
|
-
Or start from scratch:
|
|
19
|
-
rails generate fuik:provider custom_provider my_event
|
|
20
|
-
|
|
21
|
-
4. View received webhooks at:
|
|
22
|
-
GET /webhooks
|
|
23
|
-
|
|
24
|
-
===============================================================================
|