workato-connector-sdk 0.1.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 +7 -0
- data/LICENSE.md +20 -0
- data/README.md +1093 -0
- data/exe/workato +5 -0
- data/lib/workato/cli/edit_command.rb +71 -0
- data/lib/workato/cli/exec_command.rb +191 -0
- data/lib/workato/cli/generate_command.rb +105 -0
- data/lib/workato/cli/generators/connector_generator.rb +94 -0
- data/lib/workato/cli/generators/master_key_generator.rb +56 -0
- data/lib/workato/cli/main.rb +142 -0
- data/lib/workato/cli/push_command.rb +208 -0
- data/lib/workato/connector/sdk/account_properties.rb +60 -0
- data/lib/workato/connector/sdk/action.rb +88 -0
- data/lib/workato/connector/sdk/block_invocation_refinements.rb +30 -0
- data/lib/workato/connector/sdk/connector.rb +230 -0
- data/lib/workato/connector/sdk/dsl/account_property.rb +15 -0
- data/lib/workato/connector/sdk/dsl/call.rb +17 -0
- data/lib/workato/connector/sdk/dsl/error.rb +15 -0
- data/lib/workato/connector/sdk/dsl/http.rb +60 -0
- data/lib/workato/connector/sdk/dsl/lookup_table.rb +15 -0
- data/lib/workato/connector/sdk/dsl/time.rb +21 -0
- data/lib/workato/connector/sdk/dsl/workato_code_lib.rb +105 -0
- data/lib/workato/connector/sdk/dsl/workato_schema.rb +15 -0
- data/lib/workato/connector/sdk/dsl.rb +46 -0
- data/lib/workato/connector/sdk/errors.rb +30 -0
- data/lib/workato/connector/sdk/lookup_tables.rb +62 -0
- data/lib/workato/connector/sdk/object_definitions.rb +74 -0
- data/lib/workato/connector/sdk/operation.rb +217 -0
- data/lib/workato/connector/sdk/request.rb +399 -0
- data/lib/workato/connector/sdk/settings.rb +130 -0
- data/lib/workato/connector/sdk/summarize.rb +61 -0
- data/lib/workato/connector/sdk/trigger.rb +96 -0
- data/lib/workato/connector/sdk/version.rb +9 -0
- data/lib/workato/connector/sdk/workato_schemas.rb +37 -0
- data/lib/workato/connector/sdk/xml.rb +35 -0
- data/lib/workato/connector/sdk.rb +58 -0
- data/lib/workato/extension/array.rb +124 -0
- data/lib/workato/extension/case_sensitive_headers.rb +51 -0
- data/lib/workato/extension/currency.rb +15 -0
- data/lib/workato/extension/date.rb +14 -0
- data/lib/workato/extension/enumerable.rb +55 -0
- data/lib/workato/extension/extra_chain_cert.rb +40 -0
- data/lib/workato/extension/hash.rb +13 -0
- data/lib/workato/extension/integer.rb +17 -0
- data/lib/workato/extension/nil_class.rb +17 -0
- data/lib/workato/extension/object.rb +38 -0
- data/lib/workato/extension/phone.rb +14 -0
- data/lib/workato/extension/string.rb +268 -0
- data/lib/workato/extension/symbol.rb +13 -0
- data/lib/workato/extension/time.rb +13 -0
- data/lib/workato/testing/vcr_encrypted_cassette_serializer.rb +38 -0
- data/lib/workato/testing/vcr_multipart_body_matcher.rb +32 -0
- data/lib/workato-connector-sdk.rb +3 -0
- data/templates/.rspec.erb +3 -0
- data/templates/Gemfile.erb +10 -0
- data/templates/connector.rb.erb +37 -0
- data/templates/spec/action_spec.rb.erb +36 -0
- data/templates/spec/connector_spec.rb.erb +18 -0
- data/templates/spec/method_spec.rb.erb +13 -0
- data/templates/spec/object_definition_spec.rb.erb +18 -0
- data/templates/spec/pick_list_spec.rb.erb +13 -0
- data/templates/spec/spec_helper.rb.erb +38 -0
- data/templates/spec/trigger_spec.rb.erb +61 -0
- metadata +372 -0
@@ -0,0 +1,399 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'delegate'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'json'
|
6
|
+
require 'gyoku'
|
7
|
+
require 'net/http'
|
8
|
+
require 'net/http/digest_auth'
|
9
|
+
|
10
|
+
require_relative './block_invocation_refinements'
|
11
|
+
|
12
|
+
module Workato
|
13
|
+
module Connector
|
14
|
+
module Sdk
|
15
|
+
class Request < SimpleDelegator
|
16
|
+
using BlockInvocationRefinements
|
17
|
+
|
18
|
+
def initialize(uri, method: 'GET', connection: {}, settings: {}, action: nil)
|
19
|
+
super(nil)
|
20
|
+
@uri = uri
|
21
|
+
@authorization = (connection[:authorization] || {}).with_indifferent_access
|
22
|
+
@settings = settings
|
23
|
+
@base_uri = connection[:base_uri]&.call(settings.with_indifferent_access)
|
24
|
+
@method = method
|
25
|
+
@action = action
|
26
|
+
@headers = {}
|
27
|
+
@case_sensitive_headers = {}
|
28
|
+
@params = {}.with_indifferent_access
|
29
|
+
@render_request = ->(payload) { payload }
|
30
|
+
@parse_response = ->(payload) { payload }
|
31
|
+
@after_response = ->(_response_code, parsed_response, _response_headers) { parsed_response }
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(*args, &block)
|
35
|
+
execute!.send(*args, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def execute!
|
39
|
+
__getobj__ || __setobj__(
|
40
|
+
authorized do
|
41
|
+
begin
|
42
|
+
request = build_request
|
43
|
+
response = execute(request)
|
44
|
+
rescue RestClient::Unauthorized => e
|
45
|
+
Kernel.raise e unless @digest_auth
|
46
|
+
|
47
|
+
@digest_auth = false
|
48
|
+
headers('Authorization' => Net::HTTP::DigestAuth.new.auth_header(
|
49
|
+
URI.parse(build_url),
|
50
|
+
e.response.headers[:www_authenticate],
|
51
|
+
method.to_s.upcase
|
52
|
+
))
|
53
|
+
request = build_request
|
54
|
+
response = execute(request)
|
55
|
+
end
|
56
|
+
detect_error!(response.body)
|
57
|
+
parsed_response = @parse_response.call(response)
|
58
|
+
detect_error!(parsed_response)
|
59
|
+
within_action_context(response.code, parsed_response, response.headers, &@after_response)
|
60
|
+
end
|
61
|
+
)
|
62
|
+
rescue RestClient::Exception => e
|
63
|
+
if after_error_response_matches?(e)
|
64
|
+
return apply_after_error_response(e)
|
65
|
+
end
|
66
|
+
|
67
|
+
Kernel.raise RequestError.new(response: e.response, message: e.message, method: current_verb,
|
68
|
+
code: e.http_code)
|
69
|
+
end
|
70
|
+
|
71
|
+
def headers(headers)
|
72
|
+
@headers.merge!(headers)
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def case_sensitive_headers(headers)
|
77
|
+
@case_sensitive_headers.merge!(headers)
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def params(params)
|
82
|
+
@params.merge!(params)
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
def payload(payload = nil)
|
87
|
+
case payload
|
88
|
+
when Array
|
89
|
+
@payload ||= []
|
90
|
+
@payload += payload
|
91
|
+
when NilClass
|
92
|
+
# no-op
|
93
|
+
else
|
94
|
+
@payload ||= {}.with_indifferent_access
|
95
|
+
@payload.merge!(payload)
|
96
|
+
end
|
97
|
+
yield(@payload) if Kernel.block_given?
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
def user(usr)
|
102
|
+
@user = usr
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
def password(pwd)
|
107
|
+
@password = pwd
|
108
|
+
self
|
109
|
+
end
|
110
|
+
|
111
|
+
def digest_auth
|
112
|
+
@digest_auth = true
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
def follow_redirection
|
117
|
+
@follow_redirection = true
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
def ignore_redirection
|
122
|
+
@follow_redirection = false
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
def after_response(&after_response)
|
127
|
+
@after_response = after_response
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def after_error_response(*matches, &after_error_response)
|
132
|
+
@after_error_response_matches = matches
|
133
|
+
@after_error_response = after_error_response
|
134
|
+
self
|
135
|
+
end
|
136
|
+
|
137
|
+
def format_json
|
138
|
+
request_format_json.response_format_json
|
139
|
+
end
|
140
|
+
|
141
|
+
def request_format_json
|
142
|
+
@content_type_header = :json
|
143
|
+
@render_request = ->(payload) { ActiveSupport::JSON.encode(payload) if payload }
|
144
|
+
self
|
145
|
+
end
|
146
|
+
|
147
|
+
def response_format_json
|
148
|
+
@accept_header = :json
|
149
|
+
@parse_response = ->(payload) { ActiveSupport::JSON.decode(payload.presence || '{}') }
|
150
|
+
self
|
151
|
+
end
|
152
|
+
|
153
|
+
def format_xml(root_element_name, namespaces = {}, **options)
|
154
|
+
request_format_xml(root_element_name, namespaces).response_format_xml(**options)
|
155
|
+
end
|
156
|
+
|
157
|
+
def request_format_xml(root_element_name, namespaces = {})
|
158
|
+
@content_type_header = :xml
|
159
|
+
@render_request = Kernel.lambda { |payload|
|
160
|
+
next unless payload
|
161
|
+
|
162
|
+
Gyoku.xml({ root_element_name => payload.merge(namespaces).deep_symbolize_keys }, key_converter: :none)
|
163
|
+
}
|
164
|
+
self
|
165
|
+
end
|
166
|
+
|
167
|
+
def response_format_xml(strip_response_namespaces: false)
|
168
|
+
@accept_header = :xml
|
169
|
+
@parse_response = ->(payload) { Xml.parse_xml_to_hash(payload, strip_namespaces: strip_response_namespaces) }
|
170
|
+
self
|
171
|
+
end
|
172
|
+
|
173
|
+
def request_body(body)
|
174
|
+
@payload = body
|
175
|
+
@render_request = ->(payload) { payload }
|
176
|
+
self
|
177
|
+
end
|
178
|
+
|
179
|
+
def response_format_raw
|
180
|
+
@parse_response = Kernel.lambda do |payload|
|
181
|
+
payload.body.force_encoding(::Encoding::BINARY)
|
182
|
+
payload.body.valid_encoding? ? payload.body : payload.body.force_encoding(::Encoding::BINARY)
|
183
|
+
end
|
184
|
+
self
|
185
|
+
end
|
186
|
+
|
187
|
+
def request_format_multipart_form
|
188
|
+
@content_type_header = nil
|
189
|
+
|
190
|
+
@render_request = Kernel.lambda do |payload|
|
191
|
+
payload&.each_with_object({}) do |(name, (value, content_type, original_filename)), rendered|
|
192
|
+
rendered[name] = if content_type.present?
|
193
|
+
Part.new(name, content_type, original_filename || ::File.basename(name), value.to_s)
|
194
|
+
else
|
195
|
+
value
|
196
|
+
end
|
197
|
+
end&.merge!(multipart: true) || {}
|
198
|
+
end
|
199
|
+
|
200
|
+
self
|
201
|
+
end
|
202
|
+
|
203
|
+
def request_format_www_form_urlencoded
|
204
|
+
@content_type_header = 'application/x-www-form-urlencoded'
|
205
|
+
@render_request = Kernel.lambda { |payload| payload.to_param }
|
206
|
+
self
|
207
|
+
end
|
208
|
+
|
209
|
+
def current_verb
|
210
|
+
method
|
211
|
+
end
|
212
|
+
|
213
|
+
def current_url
|
214
|
+
build_url
|
215
|
+
end
|
216
|
+
|
217
|
+
def auth_type(auth_type)
|
218
|
+
@auth_type = auth_type
|
219
|
+
self
|
220
|
+
end
|
221
|
+
|
222
|
+
def tls_client_cert(certificate:, key:, passphrase: nil, intermediates: [])
|
223
|
+
@ssl_client_cert = OpenSSL::X509::Certificate.new(certificate)
|
224
|
+
@ssl_client_key = OpenSSL::PKey::RSA.new(key, passphrase)
|
225
|
+
@ssl_client_intermediate_certs = Array.wrap(intermediates).compact.map do |intermediate|
|
226
|
+
OpenSSL::X509::Certificate.new(intermediate)
|
227
|
+
end
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
def tls_server_certs(certificates:, strict: true)
|
232
|
+
@ssl_cert_store ||= OpenSSL::X509::Store.new
|
233
|
+
@ssl_cert_store.set_default_paths unless strict
|
234
|
+
Array.wrap(certificates).each do |certificate|
|
235
|
+
@ssl_cert_store.add_cert(OpenSSL::X509::Certificate.new(certificate))
|
236
|
+
end
|
237
|
+
self
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
attr_reader :method
|
243
|
+
|
244
|
+
def execute(request)
|
245
|
+
if @follow_redirection.nil?
|
246
|
+
request.execute
|
247
|
+
else
|
248
|
+
request.execute do |res|
|
249
|
+
case res.code
|
250
|
+
when 301, 302, 307, 308
|
251
|
+
if @follow_redirection
|
252
|
+
res.follow_redirection
|
253
|
+
else
|
254
|
+
res
|
255
|
+
end
|
256
|
+
else
|
257
|
+
res.return!
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def build_request
|
264
|
+
RestClient::Request.new(
|
265
|
+
{
|
266
|
+
method: method,
|
267
|
+
url: build_url,
|
268
|
+
headers: build_headers,
|
269
|
+
payload: @render_request.call(@payload)
|
270
|
+
}.tap do |request_hash|
|
271
|
+
if @ssl_client_cert.present? && @ssl_client_key.present?
|
272
|
+
request_hash[:ssl_client_cert] = @ssl_client_cert
|
273
|
+
request_hash[:ssl_client_key] = @ssl_client_key
|
274
|
+
end
|
275
|
+
request_hash[:ssl_cert_store] = @ssl_cert_store if @ssl_cert_store
|
276
|
+
end
|
277
|
+
).tap do |request|
|
278
|
+
request.case_sensitive_headers = @case_sensitive_headers.transform_keys(&:to_s)
|
279
|
+
if @ssl_client_intermediate_certs.present? && @ssl_client_cert.present? && @ssl_client_key.present?
|
280
|
+
request.extra_chain_cert = @ssl_client_intermediate_certs
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def build_url
|
286
|
+
uri = if @base_uri
|
287
|
+
URI.parse(@base_uri).merge(@uri)
|
288
|
+
else
|
289
|
+
URI.parse(@uri)
|
290
|
+
end
|
291
|
+
|
292
|
+
return uri.to_s unless @params.any? || @user || @password
|
293
|
+
|
294
|
+
unless @digest_auth
|
295
|
+
uri.user = URI.encode_www_form_component(@user) if @user
|
296
|
+
uri.password = URI.encode_www_form_component(@password) if @password
|
297
|
+
end
|
298
|
+
|
299
|
+
return uri.to_s unless @params.any?
|
300
|
+
|
301
|
+
query = uri.query.to_s.split('&').select(&:present?).join('&').presence
|
302
|
+
params = @params.to_param.presence
|
303
|
+
if query && params
|
304
|
+
uri.query = "#{query}&#{params}"
|
305
|
+
elsif params
|
306
|
+
uri.query = params
|
307
|
+
end
|
308
|
+
|
309
|
+
uri.to_s
|
310
|
+
end
|
311
|
+
|
312
|
+
def build_headers
|
313
|
+
headers = @headers
|
314
|
+
if @content_type_header.present? && headers.keys.none? { |key| /^content[\-_]type$/i =~ key }
|
315
|
+
headers[:content_type] = @content_type_header
|
316
|
+
end
|
317
|
+
if @accept_header && headers.keys.none? { |key| /^accept$/i =~ key }
|
318
|
+
headers[:accept] = @accept_header
|
319
|
+
end
|
320
|
+
headers.compact
|
321
|
+
end
|
322
|
+
|
323
|
+
def detect_error!(response)
|
324
|
+
error_patterns = Array.wrap(@authorization[:detect_on])
|
325
|
+
return unless error_patterns.any? { |pattern| pattern === response rescue false }
|
326
|
+
|
327
|
+
Kernel.raise(CustomRequestError, response.to_s)
|
328
|
+
end
|
329
|
+
|
330
|
+
def after_error_response_matches?(exception)
|
331
|
+
return if @after_error_response_matches.blank?
|
332
|
+
|
333
|
+
@after_error_response_matches.find do |match|
|
334
|
+
case match
|
335
|
+
when ::Integer
|
336
|
+
match == exception.http_code
|
337
|
+
when ::String
|
338
|
+
exception.message.to_s.match(match) || exception.http_body&.match(match)
|
339
|
+
when ::Regexp
|
340
|
+
match =~ exception.message || match =~ exception.http_body
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def apply_after_error_response(exception)
|
346
|
+
within_action_context(
|
347
|
+
exception.http_code,
|
348
|
+
exception.http_body,
|
349
|
+
exception.http_headers&.with_indifferent_access || {},
|
350
|
+
exception.message,
|
351
|
+
&@after_error_response
|
352
|
+
)
|
353
|
+
end
|
354
|
+
|
355
|
+
def within_action_context(*args, &block)
|
356
|
+
(@action || self).instance_exec(*args, &block)
|
357
|
+
end
|
358
|
+
|
359
|
+
def authorized
|
360
|
+
apply = @authorization[:apply] || @authorization[:credentials]
|
361
|
+
return yield unless apply
|
362
|
+
|
363
|
+
first = true
|
364
|
+
begin
|
365
|
+
settings = @settings.with_indifferent_access
|
366
|
+
if /oauth2/i =~ @authorization[:type]
|
367
|
+
instance_exec(settings, settings[:access_token], @auth_type, &apply)
|
368
|
+
else
|
369
|
+
instance_exec(settings, @auth_type, &apply)
|
370
|
+
end
|
371
|
+
yield
|
372
|
+
rescue StandardError => e
|
373
|
+
Kernel.raise e unless first
|
374
|
+
Kernel.raise e unless @action&.refresh_authorization!(
|
375
|
+
e.try(:http_code),
|
376
|
+
e.try(:http_body),
|
377
|
+
e.message,
|
378
|
+
@settings
|
379
|
+
)
|
380
|
+
|
381
|
+
first = false
|
382
|
+
retry
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
class Part < StringIO
|
387
|
+
def initialize(path, content_type, original_filename, *args)
|
388
|
+
super(*args)
|
389
|
+
@path = path
|
390
|
+
@content_type = content_type
|
391
|
+
@original_filename = original_filename
|
392
|
+
end
|
393
|
+
|
394
|
+
attr_reader :path, :content_type, :original_filename
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/encrypted_configuration'
|
4
|
+
|
5
|
+
module Workato
|
6
|
+
module Connector
|
7
|
+
module Sdk
|
8
|
+
class Settings
|
9
|
+
class << self
|
10
|
+
def from_file(path = DEFAULT_SETTINGS_PATH, name = nil)
|
11
|
+
new(path: path, name: name, encrypted: false).read
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_encrypted_file(path = DEFAULT_ENCRYPTED_SETTINGS_PATH, key_path = nil, name = nil)
|
15
|
+
new(path: path, name: name, key_path: key_path, encrypted: true).read
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_default_file(name = nil)
|
19
|
+
new(name: name).read
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(path: nil, encrypted: nil, name: nil, key_path: nil)
|
24
|
+
@path = path
|
25
|
+
@name = name
|
26
|
+
@key_path = key_path
|
27
|
+
@encrypted = encrypted
|
28
|
+
end
|
29
|
+
|
30
|
+
def read
|
31
|
+
if path.nil?
|
32
|
+
if File.exist?(DEFAULT_ENCRYPTED_SETTINGS_PATH)
|
33
|
+
@encrypted = true
|
34
|
+
@path = DEFAULT_ENCRYPTED_SETTINGS_PATH
|
35
|
+
read_encrypted_file
|
36
|
+
elsif File.exist?(DEFAULT_SETTINGS_PATH)
|
37
|
+
@encrypted = false
|
38
|
+
@path = DEFAULT_SETTINGS_PATH
|
39
|
+
read_plain_file
|
40
|
+
else
|
41
|
+
@encrypted = false
|
42
|
+
{}
|
43
|
+
end
|
44
|
+
elsif encrypted.nil?
|
45
|
+
begin
|
46
|
+
@encrypted = false
|
47
|
+
read_plain_file
|
48
|
+
rescue StandardError
|
49
|
+
@encrypted = true
|
50
|
+
read_encrypted_file
|
51
|
+
end
|
52
|
+
elsif encrypted
|
53
|
+
read_encrypted_file
|
54
|
+
else
|
55
|
+
read_plain_file
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def update(new_settings)
|
60
|
+
if encrypted
|
61
|
+
update_encrypted_file(new_settings)
|
62
|
+
else
|
63
|
+
update_plain_file(new_settings)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
attr_reader :key_path,
|
70
|
+
:name,
|
71
|
+
:path,
|
72
|
+
:encrypted
|
73
|
+
|
74
|
+
def read_plain_file
|
75
|
+
all_settings = File.open(path) do |f|
|
76
|
+
YAML.safe_load(f.read, [::Symbol]).to_hash.with_indifferent_access
|
77
|
+
end
|
78
|
+
|
79
|
+
name ? all_settings.fetch(name) : all_settings
|
80
|
+
end
|
81
|
+
|
82
|
+
def update_plain_file(new_settings)
|
83
|
+
@path ||= DEFAULT_SETTINGS_PATH
|
84
|
+
File.write(path, YAML.dump({})) unless File.exist?(path)
|
85
|
+
|
86
|
+
all_settings = self.class.from_file(path)
|
87
|
+
|
88
|
+
merge_settings(all_settings, new_settings)
|
89
|
+
|
90
|
+
File.write(path, serialize(all_settings))
|
91
|
+
end
|
92
|
+
|
93
|
+
def read_encrypted_file
|
94
|
+
all_settings = encrypted_configuration.config.with_indifferent_access
|
95
|
+
|
96
|
+
name ? all_settings.fetch(name) : all_settings
|
97
|
+
end
|
98
|
+
|
99
|
+
def update_encrypted_file(new_settings)
|
100
|
+
all_settings = encrypted_configuration.config.with_indifferent_access
|
101
|
+
|
102
|
+
merge_settings(all_settings, new_settings)
|
103
|
+
|
104
|
+
encrypted_configuration.write(serialize(all_settings))
|
105
|
+
end
|
106
|
+
|
107
|
+
def merge_settings(all_settings, new_settings)
|
108
|
+
if name
|
109
|
+
all_settings[name] = new_settings
|
110
|
+
else
|
111
|
+
all_settings.merge!(new_settings)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def encrypted_configuration
|
116
|
+
@encrypted_configuration ||= ActiveSupport::EncryptedConfiguration.new(
|
117
|
+
config_path: path,
|
118
|
+
key_path: key_path || DEFAULT_MASTER_KEY_PATH,
|
119
|
+
env_key: DEFAULT_MASTER_KEY_ENV,
|
120
|
+
raise_if_missing_key: true
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
def serialize(settings)
|
125
|
+
YAML.dump(settings.to_hash)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|