usps-imis-api 0.11.40 → 0.11.42
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 +1 -1
- data/lib/usps/imis/api.rb +38 -16
- data/lib/usps/imis/base_data.rb +25 -3
- data/lib/usps/imis/blank_object.rb +2 -0
- data/lib/usps/imis/business_object.rb +11 -5
- data/lib/usps/imis/command_line/interface.rb +9 -6
- 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 +28 -4
- data/lib/usps/imis/errors/response_error.rb +1 -1
- data/lib/usps/imis/mapper.rb +5 -5
- data/lib/usps/imis/panels/base_panel.rb +1 -1
- data/lib/usps/imis/properties.rb +4 -1
- 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: db2bc7a4cecec659c0b9d6c86ec8a5819f066537f35b0db089ca5f7df243c597
|
|
4
|
+
data.tar.gz: 7945390fbd0d073799a01e25cbfd9ffcd6a590da818055a39a7c6368a881e787
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 20eca697722eb6ef3d502afa3b87f46655feee6739eabec86580a032d28f590f29b619abdca8d25f56edcc77a7584305fe9911c73c596b5b70dd847d00fb1b96
|
|
7
|
+
data.tar.gz: 92676045e015b98881b8d40e5d99b9720ddae3618d3686837e6ac9ac0a5414308ba146f4a9339e64038f85c696abbc2d07f148c3a62bed14d93c9f9e7096f0b7
|
data/Readme.md
CHANGED
|
@@ -86,4 +86,4 @@ file to [rubygems.org](https://rubygems.org).
|
|
|
86
86
|
A wrapper for the CLI from this API is
|
|
87
87
|
[available for PHP](https://github.com/unitedstatespowersquadrons/imis-api-php).
|
|
88
88
|
|
|
89
|
-
You can also view the [original PHP API](https://github.com/unitedstatespowersquadrons/imis-api).
|
|
89
|
+
You can also view the (***deprecated***) [original PHP API](https://github.com/unitedstatespowersquadrons/imis-api).
|
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
|
|
@@ -138,6 +139,8 @@ module Usps
|
|
|
138
139
|
# @param id [Integer, String] iMIS ID to select for requests within the block
|
|
139
140
|
# @param certificate [String] Certificate number to convert to iMIS ID and select for requests within the block
|
|
140
141
|
# @param record_id [Integer] Record ID to select for requests within the block
|
|
142
|
+
# @yield Block context to run requests with a specific iMIS ID
|
|
143
|
+
# @yieldparam [Api]
|
|
141
144
|
#
|
|
142
145
|
# @example
|
|
143
146
|
# with(12345) do
|
|
@@ -175,7 +178,7 @@ module Usps
|
|
|
175
178
|
#
|
|
176
179
|
# @return [Usps::Imis::Query] Query wrapper
|
|
177
180
|
#
|
|
178
|
-
def query(query_name, query_params =
|
|
181
|
+
def query(query_name, query_params = {}) = Query.new(self, query_name, **query_params)
|
|
179
182
|
|
|
180
183
|
# Run requests as DSL, with specific +BusinessObject+ only maintained for this scope
|
|
181
184
|
#
|
|
@@ -183,6 +186,8 @@ module Usps
|
|
|
183
186
|
#
|
|
184
187
|
# @param business_object_name [String, Symbol] Name of the business object
|
|
185
188
|
# @param ordinal [Integer] Ordinal to build override ID param of the URL (e.g. used for Panels)
|
|
189
|
+
# @yield Block context to run requests on a specific +BusinessObject+
|
|
190
|
+
# @yieldparam [Api]
|
|
186
191
|
#
|
|
187
192
|
# @return [Usps::Imis::BusinessObject]
|
|
188
193
|
#
|
|
@@ -250,12 +255,27 @@ module Usps
|
|
|
250
255
|
{ token: @token, token_expiration: @token_expiration }
|
|
251
256
|
end
|
|
252
257
|
|
|
258
|
+
# Persistent HTTP connection for reuse across requests
|
|
259
|
+
#
|
|
260
|
+
def http_connection
|
|
261
|
+
return @http_connection if @http_connection&.started?
|
|
262
|
+
|
|
263
|
+
hostname = URI(Imis.configuration.hostname)
|
|
264
|
+
@http_connection = Net::HTTP.new(hostname.host, hostname.port).tap do |http|
|
|
265
|
+
http.use_ssl = true
|
|
266
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
267
|
+
http.open_timeout = 10
|
|
268
|
+
http.read_timeout = 30
|
|
269
|
+
http.write_timeout = 30
|
|
270
|
+
http.keep_alive_timeout = 30
|
|
271
|
+
http.start
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
253
275
|
# Ruby 3.5 instance variable filter
|
|
254
276
|
#
|
|
255
277
|
def instance_variables_to_inspect = %i[@token_expiration @imis_id]
|
|
256
278
|
|
|
257
|
-
private
|
|
258
|
-
|
|
259
279
|
# Authenticate to the iMIS API, and store the access token and expiration time
|
|
260
280
|
#
|
|
261
281
|
def authenticate
|
|
@@ -270,7 +290,7 @@ module Usps
|
|
|
270
290
|
username: Imis.configuration.username,
|
|
271
291
|
password: Imis.configuration.password
|
|
272
292
|
)
|
|
273
|
-
result = submit(
|
|
293
|
+
result = submit(request)
|
|
274
294
|
json = JSON.parse(result.body)
|
|
275
295
|
end
|
|
276
296
|
|
|
@@ -278,6 +298,8 @@ module Usps
|
|
|
278
298
|
@token_expiration = Time.now + json['expires_in'] - 60
|
|
279
299
|
end
|
|
280
300
|
|
|
301
|
+
private
|
|
302
|
+
|
|
281
303
|
# URI for the authentication endpoint
|
|
282
304
|
#
|
|
283
305
|
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)
|
|
@@ -21,6 +21,8 @@ module Usps
|
|
|
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
|
+
# @yield Block context to define additional properties with +add+
|
|
25
|
+
# @yieldparam [Properties]
|
|
24
26
|
#
|
|
25
27
|
def build(hash = {}, &) = header.merge(Properties.build(parent.api.record_id.to_s, @ordinal&.to_s, hash, &))
|
|
26
28
|
|
|
@@ -37,7 +37,7 @@ module Usps
|
|
|
37
37
|
@api = api
|
|
38
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
|
|
@@ -134,16 +134,22 @@ 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
|
+
# @param hash [Hash] Hash version of props to set (block takes priority)
|
|
143
|
+
# @yield Block context to define additional properties with +add+
|
|
144
|
+
# @yieldparam [Properties]
|
|
145
|
+
#
|
|
142
146
|
def blank_object(hash = {}, &) = BlankObject.new(self).build(hash, &)
|
|
143
147
|
|
|
144
148
|
# Create a business object for the current member, starting with a blank object and building properties
|
|
145
149
|
#
|
|
146
150
|
# @param hash [Hash] Hash version of props to set (block takes priority)
|
|
151
|
+
# @yield Block context to define additional properties with +add+
|
|
152
|
+
# @yieldparam [Properties]
|
|
147
153
|
#
|
|
148
154
|
def post_from_blank(hash = {}, &) = post(blank_object(hash, &))
|
|
149
155
|
alias create_from_blank post_from_blank
|
|
@@ -179,7 +185,7 @@ module Usps
|
|
|
179
185
|
|
|
180
186
|
existing = get
|
|
181
187
|
|
|
182
|
-
JSON.parse(JSON.dump(existing)).tap do |updated|
|
|
188
|
+
JSON.parse(JSON.dump(existing.raw)).tap do |updated|
|
|
183
189
|
# Preserve the iMIS ID, as well as the Ordinal (if present)
|
|
184
190
|
updated['Properties']['$values'], properties =
|
|
185
191
|
existing.raw['Properties']['$values'].partition { %w[ID Ordinal].include?(it['Name']) }
|
|
@@ -204,7 +210,7 @@ module Usps
|
|
|
204
210
|
def raw_object
|
|
205
211
|
raise Errors::MissingIdError if api.imis_id.nil?
|
|
206
212
|
|
|
207
|
-
response = submit(
|
|
213
|
+
response = submit(authorize(http_get))
|
|
208
214
|
klass = business_object_name == 'Party' ? PartyData : Data
|
|
209
215
|
result = klass.from_json(response.body)
|
|
210
216
|
logger.json result
|
|
@@ -217,7 +223,7 @@ module Usps
|
|
|
217
223
|
raise Errors::MissingIdError if api.imis_id.nil?
|
|
218
224
|
|
|
219
225
|
request.body = JSON.dump(body)
|
|
220
|
-
response = submit(
|
|
226
|
+
response = submit(authorize(request))
|
|
221
227
|
klass = business_object_name == 'Party' ? PartyData : Data
|
|
222
228
|
result = klass.from_json(response.body)
|
|
223
229
|
logger.json result
|
|
@@ -17,7 +17,7 @@ module Usps
|
|
|
17
17
|
local: File.join(Dir.pwd, 'imis.yml'),
|
|
18
18
|
local_dot_config: File.join(Dir.pwd, '.config', 'imis.yml'),
|
|
19
19
|
local_config: File.join(Dir.pwd, 'config', 'imis.yml'),
|
|
20
|
-
user:
|
|
20
|
+
user: File.join(Dir.home, '.config', 'imis.yml'),
|
|
21
21
|
system: '/usr/local/imis/config.yml'
|
|
22
22
|
}.freeze
|
|
23
23
|
|
|
@@ -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
|
|
@@ -31,22 +34,36 @@ module Usps
|
|
|
31
34
|
@logger_level = logger.class::SEV_LABEL[logger.level].downcase.to_sym
|
|
32
35
|
end
|
|
33
36
|
|
|
37
|
+
# Define the API environment
|
|
38
|
+
#
|
|
39
|
+
# @param env [String] Environment to use
|
|
40
|
+
#
|
|
34
41
|
def environment=(env)
|
|
35
42
|
@environment = ActiveSupport::StringInquirer.new(env.to_s)
|
|
36
43
|
end
|
|
37
44
|
|
|
45
|
+
# Override the main logger
|
|
46
|
+
#
|
|
47
|
+
# @param logger [Logger] Configured logging object
|
|
48
|
+
#
|
|
38
49
|
def logger=(logger)
|
|
39
50
|
@base_logger = logger.tap { it.formatter = LoggerFormatter.new }
|
|
40
51
|
@base_logger.singleton_class.include(LoggerHelpers)
|
|
41
52
|
@logger = ActiveSupport::TaggedLogging.new(@base_logger)
|
|
42
53
|
end
|
|
43
54
|
|
|
55
|
+
# Define the main logger
|
|
56
|
+
#
|
|
57
|
+
# @param path [path, nil] Path to write log to, or +nil+ to log to +STDOUT+
|
|
58
|
+
#
|
|
44
59
|
def logger_file=(path)
|
|
45
60
|
@logger_file = path
|
|
46
61
|
@base_logger = Logger.new(@logger_file.nil? ? $stdout : @logger_file, level: logger.level)
|
|
47
62
|
@logger = ActiveSupport::TaggedLogging.new(@base_logger)
|
|
48
63
|
end
|
|
49
64
|
|
|
65
|
+
# Current global mirror debug logger
|
|
66
|
+
#
|
|
50
67
|
def global_logger
|
|
51
68
|
return @global_logger if @global_logger
|
|
52
69
|
|
|
@@ -54,14 +71,21 @@ module Usps
|
|
|
54
71
|
@global_logger
|
|
55
72
|
end
|
|
56
73
|
|
|
74
|
+
# Current path for the global mirror debug logger
|
|
75
|
+
#
|
|
57
76
|
def global_log_path
|
|
58
|
-
defined?(@global_log_path)
|
|
77
|
+
return @global_log_path if defined?(@global_log_path)
|
|
78
|
+
|
|
79
|
+
self.global_log_path = DEFAULT_GLOBAL_LOG_PATH
|
|
59
80
|
end
|
|
60
81
|
|
|
82
|
+
# Define the global mirror debug logger
|
|
83
|
+
#
|
|
84
|
+
# @param path [path, nil] Path to write log to, or +nil+ to disable
|
|
85
|
+
#
|
|
61
86
|
def global_log_path=(path)
|
|
62
87
|
@global_log_path = path
|
|
63
88
|
@global_logger = build_global_logger
|
|
64
|
-
global_log_path
|
|
65
89
|
end
|
|
66
90
|
|
|
67
91
|
def silence!
|
|
@@ -88,7 +112,7 @@ module Usps
|
|
|
88
112
|
def filtered_parameters = %i[password]
|
|
89
113
|
|
|
90
114
|
def validate!
|
|
91
|
-
missing_config =
|
|
115
|
+
missing_config = REQUIRED.filter_map { it if public_send(it).nil? }
|
|
92
116
|
return if missing_config.empty?
|
|
93
117
|
|
|
94
118
|
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
|
|
@@ -39,14 +39,14 @@ module Usps
|
|
|
39
39
|
#
|
|
40
40
|
# Only available for fields defined in +FIELD_MAPPING+
|
|
41
41
|
#
|
|
42
|
-
# @param field_key [Symbol] Internal name of the field
|
|
42
|
+
# @param field_key [String, Symbol] Internal name of the field
|
|
43
43
|
#
|
|
44
44
|
# @return Value of the field
|
|
45
45
|
#
|
|
46
46
|
def get_field(field_key)
|
|
47
47
|
missing_mapping!(field_key) unless FIELD_MAPPING.key?(field_key.to_sym)
|
|
48
48
|
|
|
49
|
-
business_object_name, field = FIELD_MAPPING[field_key]
|
|
49
|
+
business_object_name, field = FIELD_MAPPING[field_key.to_sym]
|
|
50
50
|
api.on(business_object_name)[field]
|
|
51
51
|
end
|
|
52
52
|
alias fetch get_field
|
|
@@ -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
|
@@ -10,6 +10,8 @@ module Usps
|
|
|
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
12
|
# @param hash [Hash] Hash version of props to set (block takes priority)
|
|
13
|
+
# @yield Block context to define additional properties with +add+
|
|
14
|
+
# @yieldparam [Properties]
|
|
13
15
|
#
|
|
14
16
|
def self.build(id = nil, ordinal = nil, hash = {}, &) = new.build(id, ordinal, hash, &)
|
|
15
17
|
|
|
@@ -19,7 +21,7 @@ module Usps
|
|
|
19
21
|
case value
|
|
20
22
|
when String then value
|
|
21
23
|
when Symbol then value.to_s
|
|
22
|
-
when Time, DateTime then value.strftime('%Y-%m-%dT%H:%
|
|
24
|
+
when Time, DateTime then value.strftime('%Y-%m-%dT%H:%M:%S')
|
|
23
25
|
when Integer then { '$type' => 'System.Int32', '$value' => value }
|
|
24
26
|
when true, false then { '$type' => 'System.Boolean', '$value' => value }
|
|
25
27
|
else
|
|
@@ -33,6 +35,7 @@ module Usps
|
|
|
33
35
|
# @param ordinal [String] Ordinal to include in the properties before running the block
|
|
34
36
|
# @param hash [Hash] Hash version of props to set (block takes priority)
|
|
35
37
|
# @yield Block context to define additional properties with +add+
|
|
38
|
+
# @yieldparam [Properties]
|
|
36
39
|
#
|
|
37
40
|
def build(id = nil, ordinal = nil, hash = {})
|
|
38
41
|
@properties ||= []
|
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'
|