usps-imis-api 0.11.39 → 0.11.41
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/usps/imis/api.rb +35 -17
- data/lib/usps/imis/base_data.rb +25 -3
- data/lib/usps/imis/blank_object.rb +4 -2
- data/lib/usps/imis/business_object.rb +17 -13
- data/lib/usps/imis/command_line/interface.rb +8 -5
- data/lib/usps/imis/command_line/options_parser.rb +28 -65
- data/lib/usps/imis/command_line.rb +1 -0
- data/lib/usps/imis/config.rb +8 -4
- data/lib/usps/imis/errors/response_error.rb +1 -1
- data/lib/usps/imis/mapper.rb +3 -3
- data/lib/usps/imis/panels/base_panel.rb +1 -1
- data/lib/usps/imis/properties.rb +16 -5
- data/lib/usps/imis/query.rb +2 -2
- data/lib/usps/imis/requests.rb +5 -10
- data/lib/usps/imis/version.rb +1 -1
- data/lib/usps/imis.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ac3e7c47ae3555e7cb4d83bf24585b5b4ffac669c0f60dab014996566a4ad366
|
|
4
|
+
data.tar.gz: 547b0943b75e78b4ba4b968e3a780194cfe783eaef2301a4f5cacdee6e298c0e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f7009001491dd4177d883335bdd63a2049bf157bbac66295d22c789dd1755b9672d096a760a000883f6397e4ee9c74d48cebae0c1868895e46c7b63577aaae6
|
|
7
|
+
data.tar.gz: 8509266846dab5d93389ee7486afb8f987202d1cfbda01b2e59894e2e5fe6caddf7e820b2c822335c7123535fac1b0d3ada220d9deaf20bb3ab56a3284fccd37
|
data/lib/usps/imis/api.rb
CHANGED
|
@@ -62,7 +62,7 @@ module Usps
|
|
|
62
62
|
def initialize(imis_id: nil, record_id: nil)
|
|
63
63
|
self.imis_id = imis_id if imis_id
|
|
64
64
|
self.record_id = record_id if record_id
|
|
65
|
-
@logger
|
|
65
|
+
@logger = Imis.logger('Api')
|
|
66
66
|
Imis.config.validate!
|
|
67
67
|
end
|
|
68
68
|
|
|
@@ -80,10 +80,11 @@ module Usps
|
|
|
80
80
|
hex = '[0-9a-fA-F]'
|
|
81
81
|
uuid_pattern = /^#{hex}{8}-#{hex}{4}-#{hex}{4}-#{hex}{4}-#{hex}{12}$/
|
|
82
82
|
@imis_id =
|
|
83
|
-
if id.to_s.match?(uuid_pattern)
|
|
84
|
-
|
|
85
|
-
elsif id.
|
|
86
|
-
|
|
83
|
+
if id.to_s.match?(uuid_pattern) then id
|
|
84
|
+
elsif id.to_i.to_s == id.to_s.gsub(' ', '') then id.to_i
|
|
85
|
+
elsif id.nil? then nil
|
|
86
|
+
else
|
|
87
|
+
raise ArgumentError, "Invalid id: #{id.inspect}"
|
|
87
88
|
end
|
|
88
89
|
end
|
|
89
90
|
|
|
@@ -118,13 +119,13 @@ module Usps
|
|
|
118
119
|
|
|
119
120
|
logger.debug "Fetching iMIS ID for #{certificate}"
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
result = query(Imis.configuration.imis_id_query_name, { certificate: })
|
|
123
|
+
page = result.page.tap { logger.tagged('Response').debug it }
|
|
124
|
+
raise Errors::NotFoundError, 'Member not found' if page.empty?
|
|
125
|
+
|
|
126
|
+
self.imis_id = page.first['ID'].to_i
|
|
127
|
+
rescue Errors::ResponseError
|
|
128
|
+
raise Errors::NotFoundError, 'Member not found'
|
|
128
129
|
end
|
|
129
130
|
|
|
130
131
|
# Run requests as DSL, with specific iMIS ID only maintained for this scope
|
|
@@ -175,13 +176,13 @@ module Usps
|
|
|
175
176
|
#
|
|
176
177
|
# @return [Usps::Imis::Query] Query wrapper
|
|
177
178
|
#
|
|
178
|
-
def query(query_name, query_params =
|
|
179
|
+
def query(query_name, query_params = {}) = Query.new(self, query_name, **query_params)
|
|
179
180
|
|
|
180
181
|
# Run requests as DSL, with specific +BusinessObject+ only maintained for this scope
|
|
181
182
|
#
|
|
182
183
|
# If no block is given, this returns the specified +BusinessObject+.
|
|
183
184
|
#
|
|
184
|
-
# @param business_object_name [String] Name of the business object
|
|
185
|
+
# @param business_object_name [String, Symbol] Name of the business object
|
|
185
186
|
# @param ordinal [Integer] Ordinal to build override ID param of the URL (e.g. used for Panels)
|
|
186
187
|
#
|
|
187
188
|
# @return [Usps::Imis::BusinessObject]
|
|
@@ -250,12 +251,27 @@ module Usps
|
|
|
250
251
|
{ token: @token, token_expiration: @token_expiration }
|
|
251
252
|
end
|
|
252
253
|
|
|
254
|
+
# Persistent HTTP connection for reuse across requests
|
|
255
|
+
#
|
|
256
|
+
def http_connection
|
|
257
|
+
return @http_connection if @http_connection&.started?
|
|
258
|
+
|
|
259
|
+
hostname = URI(Imis.configuration.hostname)
|
|
260
|
+
@http_connection = Net::HTTP.new(hostname.host, hostname.port).tap do |http|
|
|
261
|
+
http.use_ssl = true
|
|
262
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
263
|
+
http.open_timeout = 10
|
|
264
|
+
http.read_timeout = 30
|
|
265
|
+
http.write_timeout = 30
|
|
266
|
+
http.keep_alive_timeout = 30
|
|
267
|
+
http.start
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
253
271
|
# Ruby 3.5 instance variable filter
|
|
254
272
|
#
|
|
255
273
|
def instance_variables_to_inspect = %i[@token_expiration @imis_id]
|
|
256
274
|
|
|
257
|
-
private
|
|
258
|
-
|
|
259
275
|
# Authenticate to the iMIS API, and store the access token and expiration time
|
|
260
276
|
#
|
|
261
277
|
def authenticate
|
|
@@ -270,7 +286,7 @@ module Usps
|
|
|
270
286
|
username: Imis.configuration.username,
|
|
271
287
|
password: Imis.configuration.password
|
|
272
288
|
)
|
|
273
|
-
result = submit(
|
|
289
|
+
result = submit(request)
|
|
274
290
|
json = JSON.parse(result.body)
|
|
275
291
|
end
|
|
276
292
|
|
|
@@ -278,6 +294,8 @@ module Usps
|
|
|
278
294
|
@token_expiration = Time.now + json['expires_in'] - 60
|
|
279
295
|
end
|
|
280
296
|
|
|
297
|
+
private
|
|
298
|
+
|
|
281
299
|
# URI for the authentication endpoint
|
|
282
300
|
#
|
|
283
301
|
def uri(...) = URI(File.join(Imis.configuration.hostname, AUTHENTICATION_PATH))
|
data/lib/usps/imis/base_data.rb
CHANGED
|
@@ -7,14 +7,28 @@ module Usps
|
|
|
7
7
|
module Imis
|
|
8
8
|
# Base class for API data response wrappers
|
|
9
9
|
#
|
|
10
|
-
class BaseData
|
|
10
|
+
class BaseData
|
|
11
|
+
# The raw API response hash
|
|
12
|
+
#
|
|
13
|
+
attr_reader :raw
|
|
14
|
+
|
|
15
|
+
# Create an instance from a hash
|
|
16
|
+
#
|
|
17
|
+
def self.[](hash) = new(hash)
|
|
18
|
+
|
|
11
19
|
# Load raw API response JSON to access properties
|
|
12
20
|
#
|
|
13
21
|
# @param json [String] Raw API response JSON
|
|
14
22
|
#
|
|
15
|
-
def self.from_json(json) =
|
|
23
|
+
def self.from_json(json) = new(JSON.parse(json))
|
|
24
|
+
|
|
25
|
+
def initialize(raw = {})
|
|
26
|
+
@raw = raw
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
alias to_h raw
|
|
16
30
|
|
|
17
|
-
|
|
31
|
+
def to_json(*) = raw.to_json(*)
|
|
18
32
|
|
|
19
33
|
# Access the iMIS ID property
|
|
20
34
|
#
|
|
@@ -48,6 +62,14 @@ module Usps
|
|
|
48
62
|
)
|
|
49
63
|
end
|
|
50
64
|
|
|
65
|
+
def ==(other)
|
|
66
|
+
case other
|
|
67
|
+
when BaseData then raw == other.raw
|
|
68
|
+
when Hash then raw == other
|
|
69
|
+
else super
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
51
73
|
def inspect
|
|
52
74
|
stringio = StringIO.new
|
|
53
75
|
PP.pp(self, stringio)
|
|
@@ -20,13 +20,15 @@ module Usps
|
|
|
20
20
|
|
|
21
21
|
# Build a blank object for the current iMIS ID
|
|
22
22
|
#
|
|
23
|
-
|
|
23
|
+
# @param hash [Hash] Hash version of props to set (block takes priority)
|
|
24
|
+
#
|
|
25
|
+
def build(hash = {}, &) = header.merge(Properties.build(parent.api.record_id.to_s, @ordinal&.to_s, hash, &))
|
|
24
26
|
|
|
25
27
|
private
|
|
26
28
|
|
|
27
29
|
def identity_type = 'System.Collections.ObjectModel.Collection`1[[System.String, mscorlib]], mscorlib'
|
|
28
30
|
|
|
29
|
-
def
|
|
31
|
+
def header
|
|
30
32
|
{
|
|
31
33
|
'$type' => 'Asi.Soa.Core.DataContracts.GenericEntityData, Asi.Contracts',
|
|
32
34
|
'EntityTypeName' => parent.business_object_name,
|
|
@@ -35,9 +35,9 @@ module Usps
|
|
|
35
35
|
#
|
|
36
36
|
def initialize(api, business_object_name, ordinal: nil)
|
|
37
37
|
@api = api
|
|
38
|
-
@business_object_name = business_object_name
|
|
38
|
+
@business_object_name = business_object_name.to_s
|
|
39
39
|
@ordinal = ordinal
|
|
40
|
-
@logger
|
|
40
|
+
@logger = Imis.logger('BusinessObject')
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# Run a query on the entire business object
|
|
@@ -62,7 +62,7 @@ module Usps
|
|
|
62
62
|
#
|
|
63
63
|
# If +fields+ is provided, will return only those field values
|
|
64
64
|
#
|
|
65
|
-
# @param fields [String] Field names to return
|
|
65
|
+
# @param fields [Array<String, Symbol>] Field names to return
|
|
66
66
|
#
|
|
67
67
|
# @return [Usps::Imis::Data, Array<Usps::Imis::Data>] Response data from the API
|
|
68
68
|
#
|
|
@@ -71,23 +71,23 @@ module Usps
|
|
|
71
71
|
|
|
72
72
|
# Get a single named field from a business object for the current member
|
|
73
73
|
#
|
|
74
|
-
# @param field [String] Field name to return
|
|
74
|
+
# @param field [String, Symbol] Field name to return
|
|
75
75
|
#
|
|
76
76
|
# @return Response data field value from the API
|
|
77
77
|
#
|
|
78
|
-
def get_field(field) = raw_object[field]
|
|
78
|
+
def get_field(field) = raw_object[field.to_s]
|
|
79
79
|
alias fetch get_field
|
|
80
80
|
alias [] get_field
|
|
81
81
|
|
|
82
82
|
# Get named fields from a business object for the current member
|
|
83
83
|
#
|
|
84
|
-
# @param names [Array<String>] Field names to return
|
|
84
|
+
# @param names [Array<String, Symbol>] Field names to return
|
|
85
85
|
#
|
|
86
86
|
# @return [Array] Response data from the API
|
|
87
87
|
#
|
|
88
88
|
def get_fields(*fields)
|
|
89
89
|
values = raw_object
|
|
90
|
-
fields.map { values[it] }
|
|
90
|
+
fields.map { values[it.to_s] }
|
|
91
91
|
end
|
|
92
92
|
alias fetch_all get_fields
|
|
93
93
|
|
|
@@ -134,16 +134,18 @@ module Usps
|
|
|
134
134
|
#
|
|
135
135
|
# @return [true] Only on success response (i.e. blank string from the API)
|
|
136
136
|
#
|
|
137
|
-
def delete = submit(
|
|
137
|
+
def delete = submit(authorize(http_delete)).body == '' # rubocop:disable Naming/PredicateMethod
|
|
138
138
|
alias destroy delete
|
|
139
139
|
|
|
140
140
|
# Build a blank object for the current iMIS ID
|
|
141
141
|
#
|
|
142
|
-
def blank_object(&) = BlankObject.new(self).build(&)
|
|
142
|
+
def blank_object(hash = {}, &) = BlankObject.new(self).build(hash, &)
|
|
143
143
|
|
|
144
144
|
# Create a business object for the current member, starting with a blank object and building properties
|
|
145
145
|
#
|
|
146
|
-
|
|
146
|
+
# @param hash [Hash] Hash version of props to set (block takes priority)
|
|
147
|
+
#
|
|
148
|
+
def post_from_blank(hash = {}, &) = post(blank_object(hash, &))
|
|
147
149
|
alias create_from_blank post_from_blank
|
|
148
150
|
|
|
149
151
|
# Ruby 3.5 instance variable filter
|
|
@@ -173,9 +175,11 @@ module Usps
|
|
|
173
175
|
def filter_fields(fields)
|
|
174
176
|
block_not_supported!
|
|
175
177
|
|
|
178
|
+
fields = fields.transform_keys(&:to_s)
|
|
179
|
+
|
|
176
180
|
existing = get
|
|
177
181
|
|
|
178
|
-
JSON.parse(JSON.dump(existing)).tap do |updated|
|
|
182
|
+
JSON.parse(JSON.dump(existing.raw)).tap do |updated|
|
|
179
183
|
# Preserve the iMIS ID, as well as the Ordinal (if present)
|
|
180
184
|
updated['Properties']['$values'], properties =
|
|
181
185
|
existing.raw['Properties']['$values'].partition { %w[ID Ordinal].include?(it['Name']) }
|
|
@@ -200,7 +204,7 @@ module Usps
|
|
|
200
204
|
def raw_object
|
|
201
205
|
raise Errors::MissingIdError if api.imis_id.nil?
|
|
202
206
|
|
|
203
|
-
response = submit(
|
|
207
|
+
response = submit(authorize(http_get))
|
|
204
208
|
klass = business_object_name == 'Party' ? PartyData : Data
|
|
205
209
|
result = klass.from_json(response.body)
|
|
206
210
|
logger.json result
|
|
@@ -213,7 +217,7 @@ module Usps
|
|
|
213
217
|
raise Errors::MissingIdError if api.imis_id.nil?
|
|
214
218
|
|
|
215
219
|
request.body = JSON.dump(body)
|
|
216
|
-
response = submit(
|
|
220
|
+
response = submit(authorize(request))
|
|
217
221
|
klass = business_object_name == 'Party' ? PartyData : Data
|
|
218
222
|
result = klass.from_json(response.body)
|
|
219
223
|
logger.json result
|
|
@@ -50,7 +50,7 @@ module Usps
|
|
|
50
50
|
|
|
51
51
|
configure!
|
|
52
52
|
logging!
|
|
53
|
-
@logger
|
|
53
|
+
@logger = Imis.logger('CommandLine')
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
# Run the configured action on the API
|
|
@@ -111,16 +111,15 @@ module Usps
|
|
|
111
111
|
|
|
112
112
|
def simplify(data)
|
|
113
113
|
return data.to_a if data.is_a?(Query)
|
|
114
|
-
return data
|
|
114
|
+
return data.is_a?(BaseData) ? data.raw : data if force_raw_output?
|
|
115
115
|
|
|
116
116
|
if data.is_a?(PartyData)
|
|
117
117
|
logger.debug 'Returning simplified PartyData#properties'
|
|
118
118
|
data.properties
|
|
119
|
-
elsif data.is_a?(
|
|
120
|
-
# Hash includes Usps::Imis::Data
|
|
119
|
+
elsif data.is_a?(Data)
|
|
121
120
|
logger.debug 'Returning simplified Data#properties'
|
|
122
121
|
data.properties(include_ids: options[:include_ids])
|
|
123
|
-
elsif data.is_a?(Array) && data.all?(
|
|
122
|
+
elsif data.is_a?(Array) && data.all?(Data)
|
|
124
123
|
logger.debug 'Returning simplified Array<Data#properties>'
|
|
125
124
|
data.map { it.properties(include_ids: options[:include_ids]) }
|
|
126
125
|
else
|
|
@@ -128,6 +127,8 @@ module Usps
|
|
|
128
127
|
end
|
|
129
128
|
end
|
|
130
129
|
|
|
130
|
+
def force_raw_output? = options[:raw] || RAW_HASH_RESPONSE_OPTIONS.any? { options[it] }
|
|
131
|
+
|
|
131
132
|
# :nocov:
|
|
132
133
|
def output(&)
|
|
133
134
|
if ENV.fetch('SUPPRESS_OUTPUT', false)
|
|
@@ -158,6 +159,8 @@ module Usps
|
|
|
158
159
|
global_log!(config)
|
|
159
160
|
|
|
160
161
|
config_data&.each do |key, value|
|
|
162
|
+
next unless Config::SETTABLE.include?(key)
|
|
163
|
+
|
|
161
164
|
config.public_send("#{key}=", value)
|
|
162
165
|
end
|
|
163
166
|
end
|
|
@@ -6,83 +6,46 @@ module Usps
|
|
|
6
6
|
# Command line options parser
|
|
7
7
|
#
|
|
8
8
|
class OptionsParser
|
|
9
|
-
|
|
10
|
-
# IDs
|
|
11
|
-
certificate: ['Member certificate number', { type: :string }],
|
|
12
|
-
id: ['Member iMIS ID', { type: :integer }],
|
|
13
|
-
record_id: ['Specific Record ID', { type: :integer, short: :I }],
|
|
14
|
-
uuid: ['Record UUID', { type: :string }],
|
|
15
|
-
|
|
16
|
-
# Primary interactions
|
|
17
|
-
on: ['Business Object name', { type: :string }],
|
|
18
|
-
panel: ['Panel name', { type: :string }],
|
|
19
|
-
query: ['IQA Query or Business Object name to query', { type: :string, short: :Q }],
|
|
20
|
-
mapper: ['Interact with mapped fields', { short: :M }],
|
|
21
|
-
map: ["Shorthand for #{'-Mf'.green} to access a single mapped field", { type: :string }],
|
|
22
|
-
business_objects: ['List available Business Objects'],
|
|
23
|
-
|
|
24
|
-
# Alternate verbs
|
|
25
|
-
create: ["Send a #{'POST'.cyan} request", { short: :P }],
|
|
26
|
-
delete: ["Send a #{'DELETE'.cyan} request", { short: :D }],
|
|
27
|
-
|
|
28
|
-
# Data
|
|
29
|
-
ordinal: ['Ordinal ID within a Panel', { type: :integer }],
|
|
30
|
-
field: ['Specific field to return or update', { type: :string }],
|
|
31
|
-
fields: ['Specific field(s) to return', { type: :strings, short: :F }],
|
|
32
|
-
data: ["JSON string input -- #{'STDIN'.red} takes priority", { type: :string }],
|
|
33
|
-
|
|
34
|
-
# Iteractions for supporting other language wrappers
|
|
35
|
-
auth_token: ['Return an auth token for other language wrappers', { short: :T }],
|
|
36
|
-
token: ['Provide an existing auth token', { type: :string }],
|
|
37
|
-
|
|
38
|
-
# General config
|
|
39
|
-
config: [
|
|
40
|
-
'Path to the JSON/YAML config file to use, or one of the following preset options: ' \
|
|
41
|
-
"`#{'local'.yellow}`, " \
|
|
42
|
-
"`#{'local_dot_config'.yellow}`, " \
|
|
43
|
-
"`#{'local_config'.yellow}`, " \
|
|
44
|
-
"`#{'user'.yellow}`, " \
|
|
45
|
-
"`#{'system'.yellow}`. " \
|
|
46
|
-
'If no option is provided, the first matching preset option will be automatically used.',
|
|
47
|
-
{ type: :string, short: :C }
|
|
48
|
-
],
|
|
49
|
-
show_config: ['Return the active config file path', { short: :X }],
|
|
50
|
-
raw: ['Return raw JSON output, rather than simplified data', { short: :R }],
|
|
51
|
-
include_ids: ["Include any #{'iMIS ID'.yellow} and #{'Ordinal'.yellow} properties in returned data"],
|
|
52
|
-
jsonl: ['Format array output as JSONL', { short: :j }],
|
|
53
|
-
quiet: ["Suppress logging to #{'STDERR'.red}"],
|
|
54
|
-
log: ["Redirect logging to #{'STDOUT'.red}"],
|
|
55
|
-
log_level: ['Set the logging level', { type: :string, default: 'info', short: :L }]
|
|
56
|
-
}.freeze
|
|
57
|
-
|
|
9
|
+
SOLO_FLAGS = %i[show_config auth_token business_objects].freeze
|
|
58
10
|
CONFLICTING_OPTION_GROUPS = [
|
|
59
11
|
%i[certificate id uuid],
|
|
60
12
|
%i[record_id uuid],
|
|
61
|
-
%i[on panel query mapper map
|
|
13
|
+
%i[on panel query mapper map] + SOLO_FLAGS,
|
|
62
14
|
%i[field fields map query],
|
|
63
15
|
%i[raw include_ids],
|
|
64
16
|
%i[quiet log_level],
|
|
65
17
|
%i[quiet log],
|
|
66
18
|
|
|
67
19
|
%i[create delete],
|
|
20
|
+
%i[create ordinal],
|
|
21
|
+
%i[data fields],
|
|
68
22
|
|
|
69
|
-
%i[create
|
|
70
|
-
%i[
|
|
71
|
-
%i[
|
|
72
|
-
%i[
|
|
73
|
-
%i[create fields],
|
|
74
|
-
|
|
75
|
-
%i[delete mapper],
|
|
76
|
-
%i[delete query],
|
|
77
|
-
%i[delete map],
|
|
78
|
-
%i[delete field],
|
|
79
|
-
%i[delete fields],
|
|
80
|
-
%i[delete data],
|
|
81
|
-
%i[delete raw]
|
|
23
|
+
*(SOLO_FLAGS + %i[mapper query map field fields certificate]).map { [:create, it] },
|
|
24
|
+
*(SOLO_FLAGS + %i[mapper query map field fields certificate data raw]).map { [:delete, it] },
|
|
25
|
+
*(SOLO_FLAGS + %i[mapper query map on]).map { [:ordinal, it] },
|
|
26
|
+
*(SOLO_FLAGS + %i[certificate]).map { [:data, it] }
|
|
82
27
|
].freeze
|
|
83
28
|
|
|
84
29
|
attr_reader :arguments, :options
|
|
85
30
|
|
|
31
|
+
def self.options
|
|
32
|
+
return @options if @options
|
|
33
|
+
|
|
34
|
+
raw_yaml_erb = File.read("#{File.dirname(__FILE__)}/options.yml.erb")
|
|
35
|
+
rendered_yaml = ERB.new(raw_yaml_erb).result.gsub("\x1b", '\u001b')
|
|
36
|
+
options = YAML.safe_load(rendered_yaml)
|
|
37
|
+
|
|
38
|
+
@options = options.transform_keys(&:to_sym).transform_values do |description, details|
|
|
39
|
+
next [description] if details.nil?
|
|
40
|
+
|
|
41
|
+
details = details.transform_keys(&:to_sym).each_with_object({}) do |(key, value), hash|
|
|
42
|
+
hash[key] = key == :default ? value : value.to_sym
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
[description, details]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
86
49
|
def self.banner_header(version)
|
|
87
50
|
<<~BANNER
|
|
88
51
|
#{version.bold.blue}
|
|
@@ -147,7 +110,7 @@ module Usps
|
|
|
147
110
|
banner OptionsParser.banner_header(version)
|
|
148
111
|
banner OptionsParser.banner_contents
|
|
149
112
|
|
|
150
|
-
|
|
113
|
+
OptionsParser.options.each { |option, data| opt(option, *data) }
|
|
151
114
|
CONFLICTING_OPTION_GROUPS.each { |group| conflicts(*group) }
|
|
152
115
|
|
|
153
116
|
educate_on_error
|
|
@@ -160,7 +123,7 @@ module Usps
|
|
|
160
123
|
# :nocov:
|
|
161
124
|
|
|
162
125
|
def defaults?
|
|
163
|
-
options_with_defaults =
|
|
126
|
+
options_with_defaults = OptionsParser.options.select { |_, data| data[1]&.key?(:default) }
|
|
164
127
|
|
|
165
128
|
options_with_defaults.all? { |option, data| data[1].nil? || options[option] == data[1][:default] } &&
|
|
166
129
|
options.except(*options_with_defaults.keys).values.none?
|
data/lib/usps/imis/config.rb
CHANGED
|
@@ -13,7 +13,10 @@ module Usps
|
|
|
13
13
|
class Config
|
|
14
14
|
IMIS_ROOT_URL_PROD = 'https://portal.americasboatingclub.org'
|
|
15
15
|
IMIS_ROOT_URL_DEV = 'https://abcdev.imiscloud.com'
|
|
16
|
-
|
|
16
|
+
DEFAULT_GLOBAL_LOG_PATH = '/var/log/imis/imis.log'
|
|
17
|
+
REQUIRED = %w[imis_id_query_name username password].freeze
|
|
18
|
+
OPTIONAL = %w[environment logger_file global_log_path].freeze
|
|
19
|
+
SETTABLE = (REQUIRED + OPTIONAL).freeze
|
|
17
20
|
|
|
18
21
|
attr_accessor :imis_id_query_name, :username, :password
|
|
19
22
|
attr_reader :environment, :logger, :logger_level, :logger_file
|
|
@@ -55,13 +58,14 @@ module Usps
|
|
|
55
58
|
end
|
|
56
59
|
|
|
57
60
|
def global_log_path
|
|
58
|
-
defined?(@global_log_path)
|
|
61
|
+
return @global_log_path if defined?(@global_log_path)
|
|
62
|
+
|
|
63
|
+
self.global_log_path = DEFAULT_GLOBAL_LOG_PATH
|
|
59
64
|
end
|
|
60
65
|
|
|
61
66
|
def global_log_path=(path)
|
|
62
67
|
@global_log_path = path
|
|
63
68
|
@global_logger = build_global_logger
|
|
64
|
-
global_log_path
|
|
65
69
|
end
|
|
66
70
|
|
|
67
71
|
def silence!
|
|
@@ -88,7 +92,7 @@ module Usps
|
|
|
88
92
|
def filtered_parameters = %i[password]
|
|
89
93
|
|
|
90
94
|
def validate!
|
|
91
|
-
missing_config =
|
|
95
|
+
missing_config = REQUIRED.filter_map { it if public_send(it).nil? }
|
|
92
96
|
return if missing_config.empty?
|
|
93
97
|
|
|
94
98
|
raise Errors::ConfigError, "Missing required configuration: #{missing_config.join(', ')}"
|
data/lib/usps/imis/mapper.rb
CHANGED
|
@@ -30,7 +30,7 @@ module Usps
|
|
|
30
30
|
def initialize(api = nil, imis_id: nil)
|
|
31
31
|
@api = api || Api.new
|
|
32
32
|
@api.imis_id = imis_id if imis_id
|
|
33
|
-
@logger
|
|
33
|
+
@logger = Imis.logger('Mapper')
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
# Get a member's data for a specific field by arbitrary field name
|
|
@@ -68,8 +68,8 @@ module Usps
|
|
|
68
68
|
business_objects[business_object_name] << field
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
business_objects.flat_map do |business_object_name,
|
|
72
|
-
api.on(business_object_name).get_fields(*
|
|
71
|
+
business_objects.flat_map do |business_object_name, object_fields|
|
|
72
|
+
api.on(business_object_name).get_fields(*object_fields)
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
alias fetch_all get_fields
|
data/lib/usps/imis/properties.rb
CHANGED
|
@@ -9,15 +9,17 @@ module Usps
|
|
|
9
9
|
#
|
|
10
10
|
# @param id [String] iMIS ID to include in the properties before running the block
|
|
11
11
|
# @param ordinal [String] Ordinal to include in the properties before running the block
|
|
12
|
+
# @param hash [Hash] Hash version of props to set (block takes priority)
|
|
12
13
|
#
|
|
13
|
-
def self.build(id = nil, ordinal = nil, &) = new.build(id, ordinal, &)
|
|
14
|
+
def self.build(id = nil, ordinal = nil, hash = {}, &) = new.build(id, ordinal, hash, &)
|
|
14
15
|
|
|
15
16
|
# Wrap value in the API-internal type structure
|
|
16
17
|
#
|
|
17
18
|
def self.wrap(value)
|
|
18
19
|
case value
|
|
19
20
|
when String then value
|
|
20
|
-
when
|
|
21
|
+
when Symbol then value.to_s
|
|
22
|
+
when Time, DateTime then value.strftime('%Y-%m-%dT%H:%M:%S')
|
|
21
23
|
when Integer then { '$type' => 'System.Int32', '$value' => value }
|
|
22
24
|
when true, false then { '$type' => 'System.Boolean', '$value' => value }
|
|
23
25
|
else
|
|
@@ -29,14 +31,18 @@ module Usps
|
|
|
29
31
|
#
|
|
30
32
|
# @param id [String] iMIS ID to include in the properties before running the block
|
|
31
33
|
# @param ordinal [String] Ordinal to include in the properties before running the block
|
|
34
|
+
# @param hash [Hash] Hash version of props to set (block takes priority)
|
|
35
|
+
# @yield Block context to define additional properties with +add+
|
|
32
36
|
#
|
|
33
|
-
def build(id = nil, ordinal = nil)
|
|
37
|
+
def build(id = nil, ordinal = nil, hash = {})
|
|
34
38
|
@properties ||= []
|
|
35
39
|
|
|
36
40
|
add('ID', id) if id
|
|
37
41
|
add('Ordinal', ordinal) if ordinal
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
hash.each { |key, value| add(key, value) }
|
|
44
|
+
|
|
45
|
+
yield(self) if block_given?
|
|
40
46
|
|
|
41
47
|
{
|
|
42
48
|
'Properties' => {
|
|
@@ -48,10 +54,15 @@ module Usps
|
|
|
48
54
|
|
|
49
55
|
# Add an individual property to the field
|
|
50
56
|
#
|
|
57
|
+
# The last definition for a given property name will be used
|
|
58
|
+
#
|
|
51
59
|
def add(name, value)
|
|
60
|
+
existing = @properties.find { it['Name'] == name.to_s }
|
|
61
|
+
@properties.delete(existing) if existing
|
|
62
|
+
|
|
52
63
|
@properties << {
|
|
53
64
|
'$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
|
|
54
|
-
'Name' => name,
|
|
65
|
+
'Name' => name.to_s,
|
|
55
66
|
'Value' => self.class.wrap(value)
|
|
56
67
|
}
|
|
57
68
|
end
|
data/lib/usps/imis/query.rb
CHANGED
|
@@ -59,7 +59,7 @@ module Usps
|
|
|
59
59
|
@page_size = page_size
|
|
60
60
|
@offset = offset
|
|
61
61
|
@count = 0
|
|
62
|
-
@logger
|
|
62
|
+
@logger = Imis.logger('Query', query_type)
|
|
63
63
|
|
|
64
64
|
logger.tagged('Name').debug query_name
|
|
65
65
|
logger.tagged('Params').json query_params
|
|
@@ -113,7 +113,7 @@ module Usps
|
|
|
113
113
|
|
|
114
114
|
# Fetch a raw query page
|
|
115
115
|
#
|
|
116
|
-
def fetch = JSON.parse(submit(
|
|
116
|
+
def fetch = JSON.parse(submit(authorize(http_get)).body)
|
|
117
117
|
|
|
118
118
|
# Reset query paging progress
|
|
119
119
|
#
|
data/lib/usps/imis/requests.rb
CHANGED
|
@@ -7,23 +7,18 @@ module Usps
|
|
|
7
7
|
module Requests
|
|
8
8
|
private
|
|
9
9
|
|
|
10
|
-
def logger = raise("#{self.class.name} must implement #logger")
|
|
10
|
+
def logger = raise(Errors::ApiError, "#{self.class.name} must implement #logger")
|
|
11
11
|
|
|
12
12
|
def token = api.token
|
|
13
13
|
def token_expiration = api.token_expiration
|
|
14
|
-
def authenticate = api.
|
|
14
|
+
def authenticate = api.authenticate
|
|
15
15
|
|
|
16
16
|
def http_get = Net::HTTP::Get.new(uri)
|
|
17
17
|
def http_put = Net::HTTP::Put.new(uri)
|
|
18
18
|
def http_post = Net::HTTP::Post.new(uri(id: ''))
|
|
19
19
|
def http_delete = Net::HTTP::Delete.new(uri)
|
|
20
20
|
|
|
21
|
-
def client(
|
|
22
|
-
Net::HTTP.new(uri.host, uri.port).tap do |http|
|
|
23
|
-
http.use_ssl = true
|
|
24
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
25
|
-
end
|
|
26
|
-
end
|
|
21
|
+
def client = respond_to?(:http_connection) ? http_connection : api.http_connection
|
|
27
22
|
|
|
28
23
|
# Authorize a request prior to submitting
|
|
29
24
|
#
|
|
@@ -37,13 +32,13 @@ module Usps
|
|
|
37
32
|
request.tap { it.add_field('Authorization', "Bearer #{token}") }
|
|
38
33
|
end
|
|
39
34
|
|
|
40
|
-
def submit(
|
|
35
|
+
def submit(request)
|
|
41
36
|
logger.info 'Submitting request to iMIS'
|
|
42
37
|
logger.tagged('Request') do
|
|
43
38
|
logger.debug "#{request.class.name.demodulize.upcase} #{uri}"
|
|
44
39
|
logger.json sanitized_request_body(request)
|
|
45
40
|
|
|
46
|
-
client
|
|
41
|
+
client.request(request).tap do |result|
|
|
47
42
|
raise Errors::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
|
|
48
43
|
|
|
49
44
|
logger.info 'Request succeeded'
|
data/lib/usps/imis/version.rb
CHANGED
data/lib/usps/imis.rb
CHANGED
|
@@ -12,7 +12,7 @@ require 'active_support/core_ext/object/to_query'
|
|
|
12
12
|
require 'active_support/core_ext/enumerable'
|
|
13
13
|
require 'active_support/string_inquirer'
|
|
14
14
|
require 'logger'
|
|
15
|
-
require 'active_support/isolated_execution_state' # Fix
|
|
15
|
+
require 'active_support/isolated_execution_state' # Fix constant loading issue with TaggedLogging
|
|
16
16
|
require 'active_support/tagged_logging'
|
|
17
17
|
|
|
18
18
|
require 'dotenv/load'
|