trailblazer-endpoint 0.0.2 → 0.0.7

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +16 -0
  3. data/Appraisals +5 -0
  4. data/CHANGES.md +28 -0
  5. data/README.md +40 -5
  6. data/Rakefile +7 -1
  7. data/gemfiles/rails_app.gemfile +12 -0
  8. data/lib/trailblazer/endpoint.rb +55 -16
  9. data/lib/trailblazer/endpoint/adapter.rb +30 -121
  10. data/lib/trailblazer/endpoint/builder.rb +1 -1
  11. data/lib/trailblazer/endpoint/controller.rb +223 -0
  12. data/lib/trailblazer/endpoint/dsl.rb +31 -0
  13. data/lib/trailblazer/endpoint/options.rb +92 -0
  14. data/lib/trailblazer/endpoint/protocol.rb +7 -11
  15. data/lib/trailblazer/endpoint/protocol/cipher.rb +27 -0
  16. data/lib/trailblazer/endpoint/protocol/controller.rb +93 -0
  17. data/lib/trailblazer/endpoint/protocol/find_process_model.rb +15 -0
  18. data/lib/trailblazer/endpoint/version.rb +1 -1
  19. data/test/adapter/api_test.rb +6 -11
  20. data/test/adapter/web_test.rb +2 -5
  21. data/test/config_test.rb +128 -0
  22. data/test/docs/controller_test.rb +340 -58
  23. data/test/endpoint_test.rb +1 -1
  24. data/test/rails-app/.gitignore +8 -2
  25. data/test/rails-app/.ruby-version +1 -0
  26. data/test/rails-app/Gemfile +21 -9
  27. data/test/rails-app/Gemfile.lock +173 -118
  28. data/test/rails-app/app/concepts/app/api/v1/representer/errors.rb +16 -0
  29. data/test/rails-app/app/concepts/auth/jwt.rb +35 -0
  30. data/test/rails-app/app/concepts/auth/operation/authenticate.rb +32 -0
  31. data/test/rails-app/app/concepts/auth/operation/policy.rb +9 -0
  32. data/test/rails-app/app/concepts/song/cell/create.rb +4 -0
  33. data/test/rails-app/app/concepts/song/cell/new.rb +4 -0
  34. data/test/rails-app/app/concepts/song/operation/create.rb +17 -0
  35. data/test/rails-app/app/concepts/song/operation/show.rb +10 -0
  36. data/test/rails-app/app/concepts/song/representer.rb +5 -0
  37. data/test/rails-app/app/concepts/song/view/create.erb +1 -0
  38. data/test/rails-app/app/concepts/song/view/new.erb +1 -0
  39. data/test/rails-app/app/controllers/api/v1/songs_controller.rb +41 -0
  40. data/test/rails-app/app/controllers/application_controller.rb +8 -1
  41. data/test/rails-app/app/controllers/application_controller/api.rb +107 -0
  42. data/test/rails-app/app/controllers/application_controller/web.rb +45 -0
  43. data/test/rails-app/app/controllers/auth_controller.rb +44 -0
  44. data/test/rails-app/app/controllers/home_controller.rb +5 -0
  45. data/test/rails-app/app/controllers/songs_controller.rb +245 -13
  46. data/test/rails-app/app/models/song.rb +6 -0
  47. data/test/rails-app/app/models/user.rb +7 -0
  48. data/test/rails-app/bin/bundle +114 -0
  49. data/test/rails-app/bin/rails +4 -0
  50. data/test/rails-app/bin/rake +4 -0
  51. data/test/rails-app/bin/setup +33 -0
  52. data/test/rails-app/config/application.rb +26 -3
  53. data/test/rails-app/config/credentials.yml.enc +1 -0
  54. data/test/rails-app/config/database.yml +2 -2
  55. data/test/rails-app/config/environments/development.rb +7 -17
  56. data/test/rails-app/config/environments/production.rb +28 -23
  57. data/test/rails-app/config/environments/test.rb +10 -12
  58. data/test/rails-app/config/initializers/application_controller_renderer.rb +6 -4
  59. data/test/rails-app/config/initializers/cors.rb +16 -0
  60. data/test/rails-app/config/initializers/trailblazer.rb +2 -0
  61. data/test/rails-app/config/locales/en.yml +11 -1
  62. data/test/rails-app/config/master.key +1 -0
  63. data/test/rails-app/config/routes.rb +26 -4
  64. data/test/rails-app/db/schema.rb +15 -0
  65. data/test/rails-app/test/controllers/api_songs_controller_test.rb +87 -0
  66. data/test/rails-app/test/controllers/songs_controller_test.rb +146 -144
  67. data/test/rails-app/test/test_helper.rb +7 -1
  68. data/test/test_helper.rb +0 -2
  69. data/trailblazer-endpoint.gemspec +2 -1
  70. metadata +73 -22
  71. data/test/rails-app/config/initializers/cookies_serializer.rb +0 -5
  72. data/test/rails-app/config/initializers/new_framework_defaults.rb +0 -24
  73. data/test/rails-app/config/initializers/session_store.rb +0 -3
  74. data/test/rails-app/config/secrets.yml +0 -22
  75. data/test/rails-app/test/helpers/.keep +0 -0
  76. data/test/rails-app/test/integration/.keep +0 -0
  77. data/test/rails-app/test/mailers/.keep +0 -0
  78. data/test/rails-app/vendor/assets/javascripts/.keep +0 -0
  79. data/test/rails-app/vendor/assets/stylesheets/.keep +0 -0
@@ -35,7 +35,7 @@ module Trailblazer
35
35
  def endpoint_for(id:, builder:, default_options:, **config)
36
36
  options = build_options_for(builder: builder, **config)
37
37
 
38
- return id, Trailblazer::Endpoint.build(default_options.merge(options[:options_for_build]), &options[:protocol_block])
38
+ return id, Trailblazer::Endpoint.build(default_options.merge(options[:options_for_build]).merge(protocol_block: options[:protocol_block]))
39
39
  end
40
40
 
41
41
  # {dsl_options} being something like
@@ -0,0 +1,223 @@
1
+ module Trailblazer
2
+ class Endpoint
3
+ module Controller
4
+ def self.extended(extended)
5
+ extended.extend Trailblazer::Endpoint::Options::DSL # ::directive
6
+ extended.extend Trailblazer::Endpoint::Options::DSL::Inherit
7
+ extended.extend Trailblazer::Endpoint::Options # ::options_for
8
+ extended.extend DSL::Endpoint
9
+
10
+ extended.include InstanceMethods # {#endpoint_for}
11
+
12
+ # DISCUSS: hmm
13
+ extended.directive :generic_options, ->(*) { Hash.new } # for Controller::endpoint
14
+ extended.directive :options_for_flow_options, ->(*) { Hash.new }
15
+ extended.directive :options_for_endpoint, ->(*) { Hash.new }
16
+ extended.directive :options_for_domain_ctx, ->(*) { Hash.new }
17
+ end
18
+
19
+ # @experimental
20
+ # TODO: test application_controller with and without dsl/api
21
+
22
+ def self.module(framework: :rails, api: false, dsl: false, application_controller: false)
23
+ if application_controller && !api && !dsl # FIXME: not tested! this is useful for an actual AppController with block_options or flow_options settings, "globally"
24
+ Module.new do
25
+ def self.included(includer)
26
+ includer.extend(Controller) # only ::directive and friends.
27
+ end
28
+ end
29
+ elsif api
30
+ Module.new do
31
+ @application_controller = application_controller
32
+ def self.included(includer)
33
+ if @application_controller
34
+ includer.extend Controller
35
+ end
36
+ includer.include(InstanceMethods::API)
37
+ end
38
+ end
39
+ elsif dsl
40
+ Module.new do
41
+ @application_controller = application_controller
42
+ def self.included(includer)
43
+ if @application_controller
44
+ includer.extend Controller
45
+ end
46
+ includer.include Trailblazer::Endpoint::Controller::InstanceMethods::DSL
47
+ includer.include Trailblazer::Endpoint::Controller::Rails
48
+ includer.extend Trailblazer::Endpoint::Controller::Rails::DefaultBlocks
49
+ includer.extend Trailblazer::Endpoint::Controller::Rails::DefaultParams
50
+ includer.include Trailblazer::Endpoint::Controller::Rails::Process
51
+ end
52
+ end # Module
53
+ else
54
+ raise
55
+ end
56
+ end
57
+
58
+ module Rails
59
+ module Process
60
+ def send_action(action_name)
61
+ puts "@@@@@>>>>>>> #{action_name.inspect}"
62
+
63
+ dsl = send(action_name) # call the actual controller action.
64
+
65
+ options, block_options = dsl.to_args(self.class.options_for(:options_for_block_options, controller: self)) # {success_block:, failure_block:, protocol_failure_block:}
66
+ # now we know the authorative blocks
67
+
68
+ Controller.advance_endpoint_for_controller(**options, block_options: block_options, config_source: self.class, controller: self)
69
+ end
70
+
71
+ end # Process
72
+
73
+ # The three default handlers for {Endpoint::with_or_etc}
74
+ # @experimental
75
+ module DefaultBlocks
76
+ def self.extended(extended)
77
+ extended.directive :options_for_block_options, Controller.method(:options_for_block_options)
78
+ end
79
+ end
80
+ # @experimental
81
+ module DefaultParams
82
+ def self.extended(extended)
83
+ extended.directive :options_for_domain_ctx, ->(ctx, controller:, **) { {params: controller.params} }
84
+ end
85
+ end
86
+
87
+ end # Rails
88
+
89
+ module DSL
90
+ module Endpoint
91
+ def self.extended(extended)
92
+ extended.directive(:endpoints, ->(*) { {} })
93
+ end
94
+
95
+ # Builds and registers an endpoint in a controller class.
96
+ def endpoint(name, **options, &block)
97
+ options = options.merge(protocol_block: block) if block_given?
98
+
99
+ return generic_endpoint_config(**name, **options) if name.is_a?(Hash)
100
+ build_endpoint(name, **options)
101
+ end
102
+
103
+ # Configures generic {:adapter}, {:protocol}, etc.
104
+ def generic_endpoint_config(**options)
105
+ self.singleton_class.define_method :generic_options do |ctx,**|
106
+ {
107
+ **options
108
+ }
109
+ end
110
+
111
+ directive :generic_options, method(:generic_options) # FIXME: do we need this?
112
+ end
113
+
114
+ def build_endpoint(name, domain_activity: name, **options)
115
+ build_options = options_for(:generic_options, {}).merge(domain_activity: domain_activity, **options) # DISCUSS: why don't we add this as another directive option/step?
116
+
117
+ endpoint = Trailblazer::Endpoint.build(build_options)
118
+
119
+ directive :endpoints, ->(*) { {name.to_s => endpoint} }
120
+ end
121
+
122
+ end
123
+ end
124
+
125
+ module InstanceMethods
126
+
127
+ def endpoint_for(name, config_source: self.class)
128
+ config_source.options_for(:endpoints, {}).fetch(name.to_s) # TODO: test non-existant endpoint
129
+ end
130
+
131
+ module DSL
132
+ def endpoint(name, **action_options, &block)
133
+ action_options = {controller: self}.merge(action_options) # FIXME: redundant with {API#endpoint}
134
+
135
+ endpoint = endpoint_for(name)
136
+
137
+ invoke_endpoint_with_dsl(endpoint: endpoint, **action_options, &block)
138
+ end
139
+
140
+ def invoke_endpoint_with_dsl(options, &block)
141
+ _dsl = Trailblazer::Endpoint::DSL::Runtime.new(options, block) # provides #Or etc, is returned to {Controller#call}
142
+ end
143
+ end
144
+
145
+ module API
146
+ def endpoint(name, config_source: self.class, **action_options)
147
+ endpoint = endpoint_for(name, config_source: config_source)
148
+
149
+ action_options = {controller: self}.merge(action_options) # FIXME: redundant with {InstanceMethods#endpoint}
150
+
151
+ block_options = config_source.options_for(:options_for_block_options, **action_options)
152
+ block_options = Trailblazer::Endpoint::Options.merge_with(action_options, block_options)
153
+
154
+ signal, (ctx, _) = Trailblazer::Endpoint::Controller.advance_endpoint_for_controller(
155
+ endpoint: endpoint,
156
+ block_options: block_options,
157
+ config_source: config_source,
158
+ **action_options
159
+ )
160
+
161
+ ctx
162
+ end
163
+ end # API
164
+ end
165
+
166
+
167
+ def self.advance_endpoint_for_controller(endpoint:, block_options:, **action_options)
168
+ domain_ctx, endpoint_options, flow_options = compile_options_for_controller(**action_options) # controller-specific, get from directives.
169
+
170
+ endpoint_options = endpoint_options.merge(action_options) # DISCUSS
171
+
172
+ Endpoint::Controller.advance_endpoint(
173
+ endpoint: endpoint,
174
+ block_options: block_options,
175
+
176
+ domain_ctx: domain_ctx,
177
+ endpoint_options: endpoint_options,
178
+ flow_options: flow_options,
179
+ )
180
+ end
181
+
182
+ def self.compile_options_for_controller(options_for_domain_ctx: nil, config_source:, **action_options)
183
+ flow_options = config_source.options_for(:options_for_flow_options, **action_options)
184
+ endpoint_options = config_source.options_for(:options_for_endpoint, **action_options) # "class level"
185
+ domain_ctx = options_for_domain_ctx || config_source.options_for(:options_for_domain_ctx, **action_options)
186
+
187
+ return domain_ctx, endpoint_options, flow_options
188
+ end
189
+
190
+ # Ultimate low-level entry point.
191
+ # Remember that you don't _have_ to use Endpoint.with_or_etc to invoke an endpoint.
192
+ def self.advance_endpoint(endpoint:, block_options:, domain_ctx:, endpoint_options:, flow_options:)
193
+
194
+ # build Context(ctx),
195
+ args, _ = Trailblazer::Endpoint.arguments_for(
196
+ domain_ctx: domain_ctx,
197
+ flow_options: flow_options,
198
+ **endpoint_options,
199
+ )
200
+
201
+ signal, (ctx, _ ) = Trailblazer::Endpoint.with_or_etc(
202
+ endpoint,
203
+ args, # [ctx, flow_options]
204
+
205
+ **block_options,
206
+ # success_block: success_block,
207
+ # failure_block: failure_block,
208
+ # protocol_failure_block: protocol_failure_block,
209
+ )
210
+ end
211
+
212
+ # Default blocks for the {Adapter}.
213
+ def self.options_for_block_options(ctx, controller:, **)
214
+ {
215
+ success_block: ->(ctx, endpoint_ctx:, **) { controller.head 200 },
216
+ failure_block: ->(ctx, **) { controller.head 422 },
217
+ protocol_failure_block: ->(ctx, endpoint_ctx:, **) { controller.head endpoint_ctx[:status] }
218
+ }
219
+ end
220
+
221
+ end # Controller
222
+ end
223
+ end
@@ -0,0 +1,31 @@
1
+ module Trailblazer
2
+ class Endpoint
3
+ module DSL
4
+ # Run before the endpoint is invoked. This collects the blocks from the controller.
5
+ class Runtime < Struct.new(:options, :success_block, :failure_block, :protocol_failure_block)
6
+
7
+ def failure(&block)
8
+ self.failure_block = block
9
+ self
10
+ end
11
+
12
+ alias_method :Or, :failure
13
+
14
+ def protocol_failure(&block)
15
+ self.protocol_failure_block = block
16
+ self
17
+ end
18
+
19
+ # #call
20
+ def to_args(default_block_options)
21
+ return options,
22
+ default_block_options.merge( # this adds :invoke.
23
+ success_block: success_block || default_block_options[:success_block],
24
+ failure_block: failure_block || default_block_options[:failure_block],
25
+ protocol_failure_block: protocol_failure_block || default_block_options[:protocol_failure_block]
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,92 @@
1
+ # DISCUSS: the generic inheritance/Options logic might be extracted to trailblazer-config or something.
2
+ # it is completely independent and could be helpful for many other configurations.
3
+ module Trailblazer
4
+ class Endpoint
5
+ module Options
6
+ module DSL
7
+ def directive(directive_name, *callables, inherit: superclass)
8
+ options = {}
9
+
10
+ if inherit
11
+ options[:base_class] = instance_variable_get(:@normalizers)[directive_name] || Trailblazer::Activity::Path # FIXME
12
+ end
13
+
14
+ @normalizers[directive_name] = Trailblazer::Endpoint::Normalizer.Options(directive_name, *callables, **options) # DISCUSS: allow multiple calls?
15
+ end
16
+
17
+ # Called in {Endpoint::Controller}.
18
+ def self.extended(extended) # TODO: let's hope this is only called once per hierachy :)
19
+ extended.instance_variable_set(:@normalizers, {})
20
+ end
21
+
22
+ module Inherit
23
+ def inherited(subclass)
24
+ super
25
+
26
+ subclass.instance_variable_set(:@normalizers, @normalizers.dup)
27
+ end
28
+ end
29
+ end
30
+
31
+ def options_for(directive_name, runtime_options)
32
+ normalizer = @normalizers.fetch(directive_name)
33
+
34
+ ctx = Trailblazer::Context(runtime_options, {})
35
+
36
+ # signal, (ctx, ) = Trailblazer::Developer.wtf?(normalizer, [ctx])
37
+ signal, (ctx, ) = Trailblazer::Activity::TaskWrap.invoke(normalizer, [ctx])
38
+
39
+ _, options = ctx.decompose
40
+ options
41
+ end
42
+
43
+
44
+ # Merge {merged} into {hash}, but only keys that exist in {hash}.
45
+ def self.merge_with(merged, hash)
46
+ keys = hash.keys
47
+ merged = keys.collect { |key| merged.key?(key) ? [key, merged[key]] : nil }.compact.to_h
48
+ hash.merge(merged)
49
+ end
50
+ end # Options
51
+
52
+ module Normalizer
53
+ def self.Options(directive_name, *callables, base_class: Trailblazer::Activity::Path)
54
+ normalizer = Class.new(base_class) do
55
+ end
56
+
57
+ Normalizer.add(normalizer, directive_name, callables)
58
+ end
59
+
60
+ def self.DefaultToEmptyHash(config_name)
61
+ -> (ctx, **) { ctx[config_name] ||= {} }
62
+ end
63
+
64
+ def self.add_normalizer!(target, normalizer, config)
65
+ normalizer = Normalizer.add(normalizer, target, config) # add configure steps for {subclass} to the _new_ normalizer.
66
+ target.instance_variable_set(:@normalizer, normalizer)
67
+ target.instance_variable_set(:@config, config)
68
+ end
69
+
70
+ def self.add(normalizer, directive_name, options)
71
+ Class.new(normalizer) do
72
+ options.collect do |callable|
73
+ step task: Normalizer.CallDirective(callable, directive_name), id: "#{directive_name}=>#{callable}"
74
+ end
75
+ end
76
+ end
77
+
78
+ def self.CallDirective(callable, option_name)
79
+ ->((ctx, flow_options), *) {
80
+ config = callable.(ctx, **ctx) # e.g. ApplicationController.options_for_endpoint
81
+
82
+ # ctx[option_name] = ctx[option_name].merge(config)
83
+ config.each do |k, v|
84
+ ctx[k] = v
85
+ end
86
+
87
+ return Trailblazer::Activity::Right, [ctx, flow_options]
88
+ }
89
+ end
90
+ end # Normalizer
91
+ end
92
+ end
@@ -1,3 +1,5 @@
1
+ require "trailblazer/activity/dsl/linear"
2
+
1
3
  module Trailblazer
2
4
  class Endpoint
3
5
  # The {Protocol} implements auth*, and calls the domain OP/WF.
@@ -16,18 +18,13 @@ module Trailblazer
16
18
  class Noop < Trailblazer::Activity::Railway
17
19
  end
18
20
 
19
- class Failure < Trailblazer::Activity::End # DISCUSS: move to Act::Railway?
20
- # class Authentication < Failure
21
- # end
22
- end
23
-
24
21
  def self._Path(semantic:, &block) # DISCUSS: the problem with Path currently is https://github.com/trailblazer/trailblazer-activity-dsl-linear/issues/27
25
- Path(track_color: semantic, end_id: "End.#{semantic}", end_task: Failure.new(semantic: semantic), &block)
22
+ Path(track_color: semantic, end_id: "End.#{semantic}", end_task: Activity::End.new(semantic: semantic), &block)
26
23
  end
27
24
 
28
25
  step :authenticate, Output(:failure) => _Path(semantic: :not_authenticated) do
29
26
  # step :handle_not_authenticated
30
- end
27
+ end
31
28
 
32
29
  step :policy, Output(:failure) => _Path(semantic: :not_authorized) do # user from cookie, etc
33
30
  # step :handle_not_authorized
@@ -43,8 +40,8 @@ module Trailblazer
43
40
  # termini for the Adapter this is the only way to get it working right now.
44
41
  # FIXME: is this really the only way to add an {End} to all this?
45
42
  @state.update_sequence do |sequence:, **|
46
- sequence = Activity::Path::DSL.append_end(sequence, task: Failure.new(semantic: :not_found), magnetic_to: :not_found, id: "End.not_found")
47
- sequence = Activity::Path::DSL.append_end(sequence, task: Failure.new(semantic: :invalid_data), magnetic_to: :invalid_data, id: "End.invalid_data")
43
+ sequence = Activity::Path::DSL.append_end(sequence, task: Activity::End.new(semantic: :not_found), magnetic_to: :not_found, id: "End.not_found")
44
+ sequence = Activity::Path::DSL.append_end(sequence, task: Activity::End.new(semantic: :invalid_data), magnetic_to: :invalid_data, id: "End.invalid_data")
48
45
 
49
46
  recompile_activity!(sequence)
50
47
 
@@ -116,7 +113,6 @@ module Trailblazer
116
113
  [[Trailblazer::Activity::TaskWrap::Pipeline.method(:insert_after), "task_wrap.call_task", ["endpoint.end_signal", method(:terminus_handler)]]]
117
114
  end
118
115
  end
119
-
120
- end
116
+ end # Protocol
121
117
  end
122
118
  end
@@ -0,0 +1,27 @@
1
+ require "openssl"
2
+
3
+ module Trailblazer
4
+ class Endpoint::Protocol
5
+ module Controller
6
+ module Cipher # FIXME: copied from Tyrant!
7
+ module_function
8
+
9
+ def encrypt_value(ctx, value:, cipher_key:, **)
10
+ cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
11
+ cipher.key = Digest::SHA1.hexdigest(cipher_key)[0..23] # ArgumentError: key must be 24 bytes
12
+ s = cipher.update(value) + cipher.final
13
+
14
+ ctx[:encrypted_value] = s.unpack('H*')[0].upcase
15
+ end
16
+
17
+ def decrypt_value(ctx, encrypted_value:, cipher_key:, **)
18
+ cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').decrypt
19
+ cipher.key = Digest::SHA1.hexdigest(cipher_key)[0..23]
20
+ s = [encrypted_value].pack("H*").unpack("C*").pack("c*")
21
+
22
+ ctx[:decrypted_value] = cipher.update(s) + cipher.final
23
+ end
24
+ end # Cipher
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,93 @@
1
+ module Trailblazer
2
+ class Endpoint::Protocol
3
+ # Deserialize incoming state.
4
+ # Serialize outgoing state.
5
+ # What else?
6
+ module Controller
7
+ module_function
8
+
9
+ def decrypt?(ctx, encrypted_resume_data:, **)
10
+ encrypted_resume_data
11
+ end
12
+
13
+ def deserialize_resume_data(ctx, decrypted_value:, **)
14
+ ctx[:resume_data] = JSON.parse(decrypted_value)
15
+ end
16
+
17
+ def deserialize_process_model?(ctx, process_model_from_resume_data:, **)
18
+ process_model_from_resume_data
19
+ end
20
+
21
+ def deserialize_process_model_id(ctx, resume_data:, **)
22
+ ctx[:process_model_id] = resume_data["id"] # DISCUSS: overriding {:process_model_id}?
23
+ end
24
+
25
+ def encrypt?(ctx, domain_ctx:, **)
26
+ ctx[:suspend_data] = domain_ctx[:suspend_data]
27
+ end
28
+
29
+ def serialize_suspend_data(ctx, suspend_data:, **)
30
+ ctx[:serialized_suspend_data] = JSON.dump(suspend_data)
31
+ end
32
+
33
+ def copy_suspend_data_to_endpoint_ctx(ctx, domain_ctx:, **)
34
+ ctx[:suspend_data] = domain_ctx[:suspend_data]
35
+ end
36
+
37
+ # FIXME: use Model() mechanics.
38
+ def deserialize_process_model_id_from_resume_data(ctx, resume_data:, **)
39
+ # DISCUSS: should we warn when overriding an existing {process_model_id}?
40
+ ctx[:process_model_id] = resume_data["id"] # DISCUSS: overriding {:process_model_id}? # FIXME: stolen from Advance___::Controller
41
+ end
42
+
43
+ def insert_deserialize_steps!(activity, deserialize_before: :policy)
44
+ activity.module_eval do
45
+ step Controller.method(:decrypt?), id: :decrypt?, before: deserialize_before # error out if no serialized_resume_data given.
46
+ step Controller::Cipher.method(:decrypt_value), id: :decrypt,
47
+ input: {cipher_key: :cipher_key, encrypted_resume_data: :encrypted_value} , before: deserialize_before,
48
+ # Output(:failure) => Track(:success),
49
+ Output(:success) => Path(connect_to: Track(:success), track_color: :deserialize, before: deserialize_before) do # usually, Path goes into {policy}
50
+
51
+ step Controller.method(:deserialize_resume_data), id: :deserialize_resume_data
52
+ # DISCUSS: unmarshall?
53
+ # step Controller.method(:deserialize_process_model_id?), id: :deserialize_process_model_id?, activity.Output(Trailblazer::Activity::Left, :failure) => activity.Id(around_activity_id)
54
+ # step Controller.method(:deserialize_process_model_id), id: :deserialize_process_model_id
55
+
56
+ step ->(*) { true } # FIXME: otherwise we can't insert an element AFTER :deserialize_resume_data
57
+ end
58
+ end
59
+ end
60
+
61
+ def insert_serialize_steps!(activity, serialize_after: :domain_activity)
62
+ activity.module_eval do
63
+ # FIXME: reverse order for insertion
64
+ step Controller::Cipher.method(:encrypt_value), id: :encrypt , after: serialize_after,
65
+ input: {cipher_key: :cipher_key, serialized_suspend_data: :value}, output: {encrypted_value: :encrypted_suspend_data}
66
+ step Controller.method(:serialize_suspend_data), id: :serialize_suspend_data , after: serialize_after
67
+ pass Controller.method(:copy_suspend_data_to_endpoint_ctx), id: :copy_suspend_data_to_endpoint_ctx , after: serialize_after
68
+ end
69
+ end
70
+
71
+ # Insert the "experimental" {find_process_model} steps
72
+ def insert_find_process_model!(protocol, **options)
73
+ protocol.module_eval do
74
+ step Subprocess(FindProcessModel), Output(:failure) => End(:not_found),
75
+ id: :find_process_model,
76
+ **options
77
+ # after: :authenticate
78
+ end
79
+
80
+ insert_copy_to_domain_ctx!(protocol, :process_model => :model)
81
+ end
82
+
83
+ def insert_copy_to_domain_ctx!(protocol, variables)
84
+ variables.each do |original_name, domain_name|
85
+ protocol.module_eval do
86
+ pass ->(ctx, domain_ctx:, **) { domain_ctx[domain_name] = ctx[original_name] if ctx.key?(original_name) },
87
+ id: :"copy_[#{original_name.inspect}]_to_domain_ctx[#{domain_name.inspect}]", before: :domain_activity
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end