view_component_reducible 0.1.3 → 0.1.4
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/lib/view_component_reducible/adapter/base.rb +7 -1
- data/lib/view_component_reducible/adapter/hidden_field.rb +1 -1
- data/lib/view_component_reducible/adapter/redis.rb +82 -0
- data/lib/view_component_reducible/adapter/session.rb +9 -2
- data/lib/view_component_reducible/configuration.rb +12 -2
- data/lib/view_component_reducible/helpers.rb +5 -3
- data/lib/view_component_reducible/version.rb +1 -1
- data/lib/view_component_reducible.rb +1 -0
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6b8576a2267bf71dae86a6339162039c3b2effa03bbd25f0eefb1fa378481244
|
|
4
|
+
data.tar.gz: eb2629af05937f40b4c87731f062f32d2640bb7a78cc0ceff20a4d6d4188c4f3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 554e95d73a13b21d4bf47185b669d63cfec7a5846668de2889b9766efb30d80e872f2739ac33e0c70af99f4673aaf74bc17cf06725c9ea68ea9dfee53d637312
|
|
7
|
+
data.tar.gz: a507b13dae0abeefa7961ac0dddf5679d22bc90e64eb6a6324481b615aa6ee68e1e81e2b6c1c3ea5383c50175940898e91b7f57fb91d2c8736d23cd20908f4f1
|
|
@@ -4,8 +4,14 @@ module ViewComponentReducible
|
|
|
4
4
|
module Adapter
|
|
5
5
|
# Base adapter interface for envelope serialization.
|
|
6
6
|
class Base
|
|
7
|
+
# @return [String]
|
|
8
|
+
def self.state_param_name
|
|
9
|
+
'vcr_state'
|
|
10
|
+
end
|
|
11
|
+
|
|
7
12
|
# @param secret [String]
|
|
8
|
-
|
|
13
|
+
# @param _kwargs [Hash]
|
|
14
|
+
def initialize(secret:, **_kwargs)
|
|
9
15
|
@secret = secret
|
|
10
16
|
end
|
|
11
17
|
|
|
@@ -23,7 +23,7 @@ module ViewComponentReducible
|
|
|
23
23
|
# @param request [ActionDispatch::Request]
|
|
24
24
|
# @return [Hash]
|
|
25
25
|
def load(request:)
|
|
26
|
-
signed = request.params.fetch(
|
|
26
|
+
signed = request.params.fetch(self.class.state_param_name)
|
|
27
27
|
verifier.verify(signed)
|
|
28
28
|
end
|
|
29
29
|
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support'
|
|
4
|
+
require 'active_support/message_verifier'
|
|
5
|
+
require 'securerandom'
|
|
6
|
+
require 'json'
|
|
7
|
+
|
|
8
|
+
module ViewComponentReducible
|
|
9
|
+
module Adapter
|
|
10
|
+
# Redis adapter storing envelope outside of the session.
|
|
11
|
+
class Redis < Base
|
|
12
|
+
DEFAULT_TTL = 900
|
|
13
|
+
DEFAULT_NAMESPACE = 'vcr'
|
|
14
|
+
|
|
15
|
+
def self.state_param_name
|
|
16
|
+
'vcr_state_key'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @param secret [String]
|
|
20
|
+
# @param redis [Object, nil]
|
|
21
|
+
# @param redis_url [String, nil]
|
|
22
|
+
# @param redis_ttl [Integer, nil]
|
|
23
|
+
# @param redis_namespace [String, nil]
|
|
24
|
+
def initialize(secret:, redis: nil, redis_url: nil, redis_ttl: DEFAULT_TTL, redis_namespace: DEFAULT_NAMESPACE)
|
|
25
|
+
super(secret:)
|
|
26
|
+
@redis = redis || build_client(redis_url)
|
|
27
|
+
@redis_ttl = redis_ttl
|
|
28
|
+
@redis_namespace = redis_namespace
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [ActiveSupport::MessageVerifier]
|
|
32
|
+
def verifier
|
|
33
|
+
@verifier ||= ActiveSupport::MessageVerifier.new(@secret, digest: 'SHA256', serializer: JSON)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @param envelope [Hash]
|
|
37
|
+
# @param request [ActionDispatch::Request]
|
|
38
|
+
# @return [String]
|
|
39
|
+
def dump(envelope, request:)
|
|
40
|
+
_ = request
|
|
41
|
+
key = SecureRandom.hex(16)
|
|
42
|
+
write(key, JSON.generate(envelope))
|
|
43
|
+
verifier.generate({ 'k' => key })
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @param request [ActionDispatch::Request]
|
|
47
|
+
# @return [Hash]
|
|
48
|
+
def load(request:)
|
|
49
|
+
signed = request.params.fetch(self.class.state_param_name)
|
|
50
|
+
payload = verifier.verify(signed)
|
|
51
|
+
key = payload.fetch('k')
|
|
52
|
+
raw = @redis.get(redis_key(key))
|
|
53
|
+
raise KeyError, "Missing envelope for #{key}" if raw.nil?
|
|
54
|
+
|
|
55
|
+
JSON.parse(raw)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def build_client(redis_url)
|
|
61
|
+
require 'redis'
|
|
62
|
+
return ::Redis.new if redis_url.nil? || redis_url == ''
|
|
63
|
+
|
|
64
|
+
::Redis.new(url: redis_url)
|
|
65
|
+
rescue LoadError
|
|
66
|
+
raise LoadError, 'Redis adapter requires the redis gem. Add `gem "redis"` to your bundle.'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def write(key, payload)
|
|
70
|
+
if @redis_ttl
|
|
71
|
+
@redis.setex(redis_key(key), @redis_ttl, payload)
|
|
72
|
+
else
|
|
73
|
+
@redis.set(redis_key(key), payload)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def redis_key(key)
|
|
78
|
+
"#{@redis_namespace}:#{key}"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -8,6 +8,10 @@ module ViewComponentReducible
|
|
|
8
8
|
module Adapter
|
|
9
9
|
# Session adapter storing envelope in server session.
|
|
10
10
|
class Session < Base
|
|
11
|
+
def self.state_param_name
|
|
12
|
+
'vcr_state_key'
|
|
13
|
+
end
|
|
14
|
+
|
|
11
15
|
# @return [ActiveSupport::MessageVerifier]
|
|
12
16
|
def verifier
|
|
13
17
|
@verifier ||= ActiveSupport::MessageVerifier.new(@secret, digest: 'SHA256', serializer: JSON)
|
|
@@ -18,14 +22,17 @@ module ViewComponentReducible
|
|
|
18
22
|
# @return [String]
|
|
19
23
|
def dump(envelope, request:)
|
|
20
24
|
key = SecureRandom.hex(16)
|
|
21
|
-
|
|
25
|
+
session = request.session
|
|
26
|
+
session_keys = session.respond_to?(:keys) ? session.keys : session.to_hash.keys
|
|
27
|
+
session_keys.grep(/\Avcr:/).each { |session_key| session.delete(session_key) }
|
|
28
|
+
session["vcr:#{key}"] = envelope
|
|
22
29
|
verifier.generate({ 'k' => key })
|
|
23
30
|
end
|
|
24
31
|
|
|
25
32
|
# @param request [ActionDispatch::Request]
|
|
26
33
|
# @return [Hash]
|
|
27
34
|
def load(request:)
|
|
28
|
-
signed = request.params.fetch(
|
|
35
|
+
signed = request.params.fetch(self.class.state_param_name)
|
|
29
36
|
payload = verifier.verify(signed)
|
|
30
37
|
key = payload.fetch('k')
|
|
31
38
|
request.session.fetch("vcr:#{key}")
|
|
@@ -4,11 +4,15 @@ module ViewComponentReducible
|
|
|
4
4
|
# Global configuration for adapter and secrets.
|
|
5
5
|
class Configuration
|
|
6
6
|
# @return [Class]
|
|
7
|
-
attr_accessor :adapter, :secret
|
|
7
|
+
attr_accessor :adapter, :secret, :redis, :redis_url, :redis_ttl, :redis_namespace
|
|
8
8
|
|
|
9
9
|
def initialize
|
|
10
10
|
@adapter = Adapter::Session
|
|
11
11
|
@secret = nil
|
|
12
|
+
@redis = nil
|
|
13
|
+
@redis_url = nil
|
|
14
|
+
@redis_ttl = nil
|
|
15
|
+
@redis_namespace = nil
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
# Build adapter instance for a controller request.
|
|
@@ -19,7 +23,13 @@ module ViewComponentReducible
|
|
|
19
23
|
resolved_secret = secret || default_secret
|
|
20
24
|
raise 'ViewComponentReducible secret is missing' if resolved_secret.nil?
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
kwargs = { secret: resolved_secret }
|
|
27
|
+
kwargs[:redis] = redis if redis
|
|
28
|
+
kwargs[:redis_url] = redis_url if redis_url
|
|
29
|
+
kwargs[:redis_ttl] = redis_ttl unless redis_ttl.nil?
|
|
30
|
+
kwargs[:redis_namespace] = redis_namespace if redis_namespace
|
|
31
|
+
|
|
32
|
+
(adapter_class || adapter).new(**kwargs)
|
|
23
33
|
end
|
|
24
34
|
|
|
25
35
|
private
|
|
@@ -24,10 +24,11 @@ module ViewComponentReducible
|
|
|
24
24
|
def vcr_dispatch_form(state:, msg_type:, msg_payload: {}, target_path: nil, url: '/vcr/dispatch', &block)
|
|
25
25
|
payload = msg_payload.is_a?(String) ? msg_payload : JSON.generate(msg_payload)
|
|
26
26
|
resolved_target = target_path || vcr_envelope_path || instance_variable_get(:@vcr_current_path) || 'root'
|
|
27
|
+
state_param = ViewComponentReducible.config.adapter.state_param_name
|
|
27
28
|
|
|
28
|
-
form_tag(url, method: :post, data: { vcr_form: true }) do
|
|
29
|
+
form_tag(url, method: :post, data: { vcr_form: true, vcr_state_param: state_param }) do
|
|
29
30
|
body = [
|
|
30
|
-
hidden_field_tag(
|
|
31
|
+
hidden_field_tag(state_param, state),
|
|
31
32
|
hidden_field_tag('vcr_msg_type', msg_type),
|
|
32
33
|
hidden_field_tag('vcr_msg_payload', payload),
|
|
33
34
|
hidden_field_tag('vcr_target_path', resolved_target),
|
|
@@ -74,7 +75,8 @@ module ViewComponentReducible
|
|
|
74
75
|
if (payload.state) {
|
|
75
76
|
var boundary = document.querySelector('[data-vcr-path="' + targetPath + '"]');
|
|
76
77
|
if (boundary) {
|
|
77
|
-
|
|
78
|
+
var stateParam = form.dataset.vcrStateParam || "vcr_state";
|
|
79
|
+
boundary.querySelectorAll('input[name="' + stateParam + '"]').forEach(function(input) {
|
|
78
80
|
input.value = payload.state;
|
|
79
81
|
});
|
|
80
82
|
}
|
|
@@ -6,6 +6,7 @@ require_relative 'view_component_reducible/msg'
|
|
|
6
6
|
require_relative 'view_component_reducible/adapter/base'
|
|
7
7
|
require_relative 'view_component_reducible/adapter/hidden_field'
|
|
8
8
|
require_relative 'view_component_reducible/adapter/session'
|
|
9
|
+
require_relative 'view_component_reducible/adapter/redis'
|
|
9
10
|
require_relative 'view_component_reducible/helpers'
|
|
10
11
|
require_relative 'view_component_reducible/state/schema'
|
|
11
12
|
require_relative 'view_component_reducible/state/dsl'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: view_component_reducible
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- manabeai
|
|
@@ -65,6 +65,20 @@ dependencies:
|
|
|
65
65
|
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '6.1'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: redis
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '4.0'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '4.0'
|
|
68
82
|
- !ruby/object:Gem::Dependency
|
|
69
83
|
name: view_component
|
|
70
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,6 +108,7 @@ files:
|
|
|
94
108
|
- lib/view_component_reducible.rb
|
|
95
109
|
- lib/view_component_reducible/adapter/base.rb
|
|
96
110
|
- lib/view_component_reducible/adapter/hidden_field.rb
|
|
111
|
+
- lib/view_component_reducible/adapter/redis.rb
|
|
97
112
|
- lib/view_component_reducible/adapter/session.rb
|
|
98
113
|
- lib/view_component_reducible/component.rb
|
|
99
114
|
- lib/view_component_reducible/configuration.rb
|