usps-imis-api 0.8.0 → 0.9.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 +4 -4
- data/Gemfile.lock +1 -1
- data/Readme.md +25 -5
- data/lib/usps/imis/api.rb +7 -33
- data/lib/usps/imis/business_object.rb +1 -1
- data/lib/usps/imis/config.rb +6 -3
- data/lib/usps/imis/data.rb +18 -7
- data/lib/usps/imis/mapper.rb +6 -8
- data/lib/usps/imis/panels/base_panel.rb +2 -2
- data/lib/usps/imis/panels/education.rb +1 -1
- data/lib/usps/imis/panels/vsc.rb +1 -1
- data/lib/usps/imis/query.rb +88 -0
- data/lib/usps/imis/requests.rb +15 -1
- data/lib/usps/imis/version.rb +1 -1
- data/lib/usps/imis.rb +6 -0
- data/spec/lib/usps/imis/api_spec.rb +9 -11
- data/spec/lib/usps/imis/data_spec.rb +16 -2
- data/spec/lib/usps/imis/mapper_spec.rb +1 -1
- data/spec/lib/usps/imis/panels/education_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e94dcde6abaf560148b72523c9defe96cd30f6980631f11b79cf8b35f52a1dcc
|
|
4
|
+
data.tar.gz: a94d8ce631656ff48bf6c3b905e3e06bf130a5a658dfad737afec2be21ac1957
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c155ff3c3e0801c4cb1d738c736e7da9833b651ba56cafb5983439d8e7708f15a266f688d40672917270745b198cac6a38e86b735932c447a631b1c5922b17d
|
|
7
|
+
data.tar.gz: e99827b9bb433d673c6d76558c209f23a12aba1dbe22a674d4972f8ff97b0122374cb4ef2955c0b903ebcf5f7d20721c15b800b79cba17c304113436ea8c66a9
|
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
|
@@ -32,6 +32,10 @@ Usps::Imis.configure do |config|
|
|
|
32
32
|
config.imis_id_query_name = ENV['IMIS_ID_QUERY_NAME']
|
|
33
33
|
config.username = ENV['IMIS_USERNAME']
|
|
34
34
|
config.password = ENV['IMIS_PASSWORD']
|
|
35
|
+
|
|
36
|
+
# These options will use these defaults
|
|
37
|
+
config.logger = Logger.new($stdout)
|
|
38
|
+
config.logger.level = :info
|
|
35
39
|
end
|
|
36
40
|
```
|
|
37
41
|
|
|
@@ -120,7 +124,7 @@ To fetch a specific field from member data, run e.g.:
|
|
|
120
124
|
tot_mms = api.on('ABC_ASC_Individual_Demog').get_field('TotMMS')
|
|
121
125
|
```
|
|
122
126
|
|
|
123
|
-
You can also access fields directly on the Business Object like a Hash:
|
|
127
|
+
You can also access fields directly on the Business Object or Panel like a Hash:
|
|
124
128
|
|
|
125
129
|
```ruby
|
|
126
130
|
tot_mms = api.on('ABC_ASC_Individual_Demog')['TotMMS']
|
|
@@ -195,7 +199,15 @@ Run an IQA Query
|
|
|
195
199
|
`query_params` is a hash of shape: `{ param_name => param_value }`
|
|
196
200
|
|
|
197
201
|
```ruby
|
|
198
|
-
api.query(query_name, query_params)
|
|
202
|
+
query = api.query(query_name, query_params)
|
|
203
|
+
|
|
204
|
+
query.each do |item|
|
|
205
|
+
# Download all pages of the query, then iterate on the results
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
query.find_each do |item|
|
|
209
|
+
# Iterate one page at a time, fetching new pages automatically
|
|
210
|
+
end
|
|
199
211
|
```
|
|
200
212
|
|
|
201
213
|
### Field Mapper
|
|
@@ -229,9 +241,9 @@ vsc.get(1417)
|
|
|
229
241
|
|
|
230
242
|
# All of these options are identical
|
|
231
243
|
#
|
|
232
|
-
vsc.get(1417, 'Quantity')
|
|
244
|
+
vsc.get(1417, 'Quantity').first
|
|
233
245
|
vsc.get(1417)['Quantity']
|
|
234
|
-
vsc
|
|
246
|
+
vsc[1417, 'Quantity']
|
|
235
247
|
vsc.get(1417).raw['Properties']['$values'].find { it['Name'] == 'Quantity' }['Value']['$value']
|
|
236
248
|
vsc.get_field(1417, 'Quantity')
|
|
237
249
|
|
|
@@ -244,7 +256,7 @@ created = vsc.create(certificate: 'E136924', year: 2024, count: 42)
|
|
|
244
256
|
ordinal = created.ordinal
|
|
245
257
|
ordinal = created['Ordinal']
|
|
246
258
|
ordinal = created.raw['Properties']['$values'].find { it['Name'] == 'Ordinal' }['Value']['$value']
|
|
247
|
-
ordinal = created.raw['Identity']['IdentityElements']['$values'][1] # Value is duplicated here
|
|
259
|
+
ordinal = created.raw['Identity']['IdentityElements']['$values'][1].to_i # Value is duplicated here
|
|
248
260
|
|
|
249
261
|
vsc.update(certificate: 'E136924', year: 2024, count: 43, ordinal: ordinal)
|
|
250
262
|
|
|
@@ -314,6 +326,14 @@ end
|
|
|
314
326
|
api.with(31092).on('ABC_ASC_Individual_Demog').get_field('TotMMS')
|
|
315
327
|
```
|
|
316
328
|
|
|
329
|
+
### Data Methods
|
|
330
|
+
|
|
331
|
+
Data responses from the API can be handled as a standard Hash using the `raw` method.
|
|
332
|
+
|
|
333
|
+
If you need to access all of the property values, you can use the `properties` method.
|
|
334
|
+
By default, this will exclude the `ID` and `Ordinal` properties; they can be included with
|
|
335
|
+
`properties(include_ids: true)`.
|
|
336
|
+
|
|
317
337
|
## Test Data Mocking
|
|
318
338
|
|
|
319
339
|
You can use the provided Business Object Mock to generate stub data for rspec:
|
data/lib/usps/imis/api.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative 'requests'
|
|
4
4
|
require_relative 'business_object'
|
|
5
5
|
require_relative 'mapper'
|
|
6
|
+
require_relative 'query'
|
|
6
7
|
|
|
7
8
|
module Usps
|
|
8
9
|
module Imis
|
|
@@ -15,10 +16,6 @@ module Usps
|
|
|
15
16
|
#
|
|
16
17
|
AUTHENTICATION_PATH = 'Token'
|
|
17
18
|
|
|
18
|
-
# Endpoint for IQA query requests
|
|
19
|
-
#
|
|
20
|
-
QUERY_PATH = 'api/Query'
|
|
21
|
-
|
|
22
19
|
# API bearer token
|
|
23
20
|
#
|
|
24
21
|
attr_reader :token
|
|
@@ -54,7 +51,7 @@ module Usps
|
|
|
54
51
|
def imis_id=(id)
|
|
55
52
|
raise Errors::LockedIdError if lock_imis_id
|
|
56
53
|
|
|
57
|
-
@imis_id = id&.to_i
|
|
54
|
+
@imis_id = id&.to_i
|
|
58
55
|
end
|
|
59
56
|
|
|
60
57
|
# Convert a member's certificate number into an iMIS ID number
|
|
@@ -67,8 +64,7 @@ module Usps
|
|
|
67
64
|
raise Errors::LockedIdError if lock_imis_id
|
|
68
65
|
|
|
69
66
|
begin
|
|
70
|
-
|
|
71
|
-
@imis_id = result['Items']['$values'][0]['ID']
|
|
67
|
+
self.imis_id = query(Imis.configuration.imis_id_query_name, { certificate: }).first['ID'].to_i
|
|
72
68
|
rescue StandardError
|
|
73
69
|
raise Errors::NotFoundError, 'Member not found'
|
|
74
70
|
end
|
|
@@ -101,7 +97,7 @@ module Usps
|
|
|
101
97
|
end
|
|
102
98
|
end
|
|
103
99
|
|
|
104
|
-
#
|
|
100
|
+
# Build an IQA Query interface
|
|
105
101
|
#
|
|
106
102
|
# @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
|
|
107
103
|
# @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
|
|
@@ -109,31 +105,7 @@ module Usps
|
|
|
109
105
|
# @return [Hash] Response data from the API
|
|
110
106
|
#
|
|
111
107
|
def query(query_name, query_params = {})
|
|
112
|
-
|
|
113
|
-
path = "#{QUERY_PATH}?#{query_params.to_query}"
|
|
114
|
-
uri = URI(File.join(Imis.configuration.hostname, path))
|
|
115
|
-
request = Net::HTTP::Get.new(uri)
|
|
116
|
-
result = submit(uri, authorize(request))
|
|
117
|
-
JSON.parse(result.body)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# Run an IQA Query, paging through all responses
|
|
121
|
-
#
|
|
122
|
-
# @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
|
|
123
|
-
# @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
|
|
124
|
-
#
|
|
125
|
-
# @return [Array<Hash>] Collected response item values from the API
|
|
126
|
-
#
|
|
127
|
-
def query_all(query_name, query_params = {})
|
|
128
|
-
response = query(query_name, **query_params)
|
|
129
|
-
results = response['Items']['$values']
|
|
130
|
-
|
|
131
|
-
while response['HasNext']
|
|
132
|
-
response = query(query_name, **query_params, Offset: response['NextOffset'])
|
|
133
|
-
results += response['Items']['$values']
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
results
|
|
108
|
+
Query.new(self, query_name, query_params)
|
|
137
109
|
end
|
|
138
110
|
|
|
139
111
|
# Run requests as DSL, with specific +BusinessObject+ only maintained for this scope
|
|
@@ -178,6 +150,8 @@ module Usps
|
|
|
178
150
|
# Authenticate to the iMIS API, and store the access token and expiration time
|
|
179
151
|
#
|
|
180
152
|
def authenticate
|
|
153
|
+
Imis.logger.debug 'Authenticating with iMIS'
|
|
154
|
+
|
|
181
155
|
uri = URI(File.join(Imis.configuration.hostname, AUTHENTICATION_PATH))
|
|
182
156
|
req = Net::HTTP::Post.new(uri)
|
|
183
157
|
authentication_data = {
|
|
@@ -120,7 +120,7 @@ module Usps
|
|
|
120
120
|
return CGI.escape(id) unless id.nil?
|
|
121
121
|
return CGI.escape("~#{api.imis_id}|#{ordinal}") if ordinal
|
|
122
122
|
|
|
123
|
-
api.imis_id
|
|
123
|
+
api.imis_id.to_s
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
# Manually assemble the matching data structure, with fields in the correct order
|
data/lib/usps/imis/config.rb
CHANGED
|
@@ -8,16 +8,19 @@ module Usps
|
|
|
8
8
|
IMIS_ROOT_URL_PROD = 'https://portal.americasboatingclub.org'
|
|
9
9
|
IMIS_ROOT_URL_DEV = 'https://abcdev.imiscloud.com'
|
|
10
10
|
|
|
11
|
-
attr_accessor :imis_id_query_name, :username, :password
|
|
12
|
-
attr_reader :environment
|
|
11
|
+
attr_accessor :imis_id_query_name, :username, :password, :logger
|
|
12
|
+
attr_reader :environment, :logger_level
|
|
13
13
|
|
|
14
14
|
def initialize
|
|
15
15
|
@environment = defined?(Rails) ? Rails.env : ActiveSupport::StringInquirer.new('development')
|
|
16
16
|
@imis_id_query_name = ENV.fetch('IMIS_ID_QUERY_NAME', nil)
|
|
17
17
|
@username = ENV.fetch('IMIS_USERNAME', nil)
|
|
18
18
|
@password = ENV.fetch('IMIS_PASSWORD', nil)
|
|
19
|
+
@logger = Logger.new($stdout, level: :info)
|
|
19
20
|
|
|
20
21
|
yield self if block_given?
|
|
22
|
+
|
|
23
|
+
@logger_level = logger.class::SEV_LABEL[logger.level].downcase.to_sym
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
def environment=(env)
|
|
@@ -37,7 +40,7 @@ module Usps
|
|
|
37
40
|
|
|
38
41
|
# Ruby 3.5 instance variable filter
|
|
39
42
|
#
|
|
40
|
-
def instance_variables_to_inspect = %i[@environment @imis_id_query_name @username]
|
|
43
|
+
def instance_variables_to_inspect = %i[@environment @imis_id_query_name @username @logger_level]
|
|
41
44
|
end
|
|
42
45
|
end
|
|
43
46
|
end
|
data/lib/usps/imis/data.rb
CHANGED
|
@@ -16,14 +16,18 @@ module Usps
|
|
|
16
16
|
|
|
17
17
|
alias raw to_h
|
|
18
18
|
|
|
19
|
+
# The Business Object or Panel name
|
|
20
|
+
#
|
|
21
|
+
def entity = raw['EntityTypeName']
|
|
22
|
+
|
|
19
23
|
# Access the iMIS ID property
|
|
20
24
|
#
|
|
21
|
-
def imis_id = self['ID']
|
|
25
|
+
def imis_id = self['ID'].to_i
|
|
22
26
|
alias id imis_id
|
|
23
27
|
|
|
24
28
|
# Access the Ordinal identifier property (if present)
|
|
25
29
|
#
|
|
26
|
-
def ordinal = self['Ordinal']
|
|
30
|
+
def ordinal = self['Ordinal']&.to_i
|
|
27
31
|
|
|
28
32
|
# Access an individual property value by name
|
|
29
33
|
#
|
|
@@ -35,6 +39,17 @@ module Usps
|
|
|
35
39
|
value.is_a?(String) ? value : value['$value']
|
|
36
40
|
end
|
|
37
41
|
|
|
42
|
+
# Hash of all property names to values
|
|
43
|
+
#
|
|
44
|
+
# @param include_ids [Boolean] Whether to include the iMIS ID and Ordinal
|
|
45
|
+
#
|
|
46
|
+
def properties(include_ids: false)
|
|
47
|
+
raw['Properties']['$values']
|
|
48
|
+
.map { it['Name'] }
|
|
49
|
+
.select { include_ids || !%w[ID Ordinal].include?(it) }
|
|
50
|
+
.index_with { self[it] }
|
|
51
|
+
end
|
|
52
|
+
|
|
38
53
|
def inspect
|
|
39
54
|
stringio = StringIO.new
|
|
40
55
|
PP.pp(self, stringio)
|
|
@@ -42,11 +57,7 @@ module Usps
|
|
|
42
57
|
end
|
|
43
58
|
|
|
44
59
|
def pretty_print(pp)
|
|
45
|
-
data = {
|
|
46
|
-
entity_type_name: raw['EntityTypeName'],
|
|
47
|
-
imis_id:,
|
|
48
|
-
ordinal:
|
|
49
|
-
}.compact
|
|
60
|
+
data = { entity:, imis_id:, ordinal: }.compact
|
|
50
61
|
|
|
51
62
|
pp.group(1, "#<#{self.class}", '>') do
|
|
52
63
|
data.each do |key, value|
|
data/lib/usps/imis/mapper.rb
CHANGED
|
@@ -36,7 +36,7 @@ module Usps
|
|
|
36
36
|
#
|
|
37
37
|
# @param data [Hash] Conforms to pattern +{ field_key => value }+
|
|
38
38
|
#
|
|
39
|
-
# @return [Array<
|
|
39
|
+
# @return [Array<Usps::Imis::Data>] Response data from the API for each internal update request
|
|
40
40
|
#
|
|
41
41
|
def update(data)
|
|
42
42
|
updates = data.each_with_object({}) do |(field_key, value), hash|
|
|
@@ -54,15 +54,13 @@ module Usps
|
|
|
54
54
|
private
|
|
55
55
|
|
|
56
56
|
def map_update(field_name)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
missing_mapping(field_name)
|
|
62
|
-
end
|
|
57
|
+
missing_mapping!(field_name) unless FIELD_MAPPING.key?(field_name.to_sym)
|
|
58
|
+
|
|
59
|
+
business_object_name, field = FIELD_MAPPING[field_name.to_sym]
|
|
60
|
+
yield(business_object_name, field)
|
|
63
61
|
end
|
|
64
62
|
|
|
65
|
-
def missing_mapping(field_name)
|
|
63
|
+
def missing_mapping!(field_name)
|
|
66
64
|
unless ENV['TESTING']
|
|
67
65
|
# :nocov:
|
|
68
66
|
warn(
|
|
@@ -113,7 +113,7 @@ module Usps
|
|
|
113
113
|
'EntityTypeName' => business_object,
|
|
114
114
|
'IdentityElements' => {
|
|
115
115
|
'$type' => identity_type,
|
|
116
|
-
'$values' => [api.imis_id, ordinal&.to_s].compact
|
|
116
|
+
'$values' => [api.imis_id.to_s, ordinal&.to_s].compact
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
end
|
|
@@ -124,7 +124,7 @@ module Usps
|
|
|
124
124
|
'EntityTypeName' => 'Party',
|
|
125
125
|
'IdentityElements' => {
|
|
126
126
|
'$type' => identity_type,
|
|
127
|
-
'$values' => [api.imis_id]
|
|
127
|
+
'$values' => [api.imis_id.to_s]
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
end
|
|
@@ -14,7 +14,7 @@ module Usps
|
|
|
14
14
|
|
|
15
15
|
def payload(data)
|
|
16
16
|
build_payload(data) do |props|
|
|
17
|
-
props.add 'ID', api.imis_id
|
|
17
|
+
props.add 'ID', api.imis_id.to_s
|
|
18
18
|
props.add 'Ordinal', data[:ordinal] if data[:ordinal]
|
|
19
19
|
props.add 'ABC_EDUC_THRU_DATE', data[:thru_date] || '0001-01-01T00:00:00'
|
|
20
20
|
props.add 'ABC_ECertificate', data[:certificate]
|
data/lib/usps/imis/panels/vsc.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Usps
|
|
|
14
14
|
|
|
15
15
|
def payload(data)
|
|
16
16
|
build_payload(data) do |props|
|
|
17
|
-
props.add 'ID', api.imis_id
|
|
17
|
+
props.add 'ID', api.imis_id.to_s
|
|
18
18
|
props.add 'Ordinal', data[:ordinal] if data[:ordinal]
|
|
19
19
|
props.add 'Source_System', 'Manual ITCom Entry'
|
|
20
20
|
props.add 'ABC_ECertificate', data[:certificate]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Usps
|
|
4
|
+
module Imis
|
|
5
|
+
# API wrapper for IQA Queries
|
|
6
|
+
#
|
|
7
|
+
class Query
|
|
8
|
+
include Enumerable
|
|
9
|
+
include Requests
|
|
10
|
+
|
|
11
|
+
# Endpoint for IQA query requests
|
|
12
|
+
#
|
|
13
|
+
QUERY_PATH = 'api/Query'
|
|
14
|
+
|
|
15
|
+
# The parent +Api+ object
|
|
16
|
+
#
|
|
17
|
+
attr_reader :api
|
|
18
|
+
|
|
19
|
+
# Name of the Query to run
|
|
20
|
+
#
|
|
21
|
+
attr_reader :query_name
|
|
22
|
+
|
|
23
|
+
# Parameters for the Query
|
|
24
|
+
#
|
|
25
|
+
attr_reader :query_params
|
|
26
|
+
|
|
27
|
+
# Current offset for paging through the Query
|
|
28
|
+
#
|
|
29
|
+
attr_reader :offset
|
|
30
|
+
|
|
31
|
+
# A new instance of +Query+
|
|
32
|
+
#
|
|
33
|
+
# @param api [Api] Parent to use for making requests
|
|
34
|
+
# @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
|
|
35
|
+
# @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
|
|
36
|
+
#
|
|
37
|
+
def initialize(api, query_name, query_params)
|
|
38
|
+
@api = api
|
|
39
|
+
@query_name = query_name
|
|
40
|
+
@query_params = query_params
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Iterate through all results from the query
|
|
44
|
+
#
|
|
45
|
+
def each(&)
|
|
46
|
+
Imis.logger.info 'Running IQA Query on iMIS'
|
|
47
|
+
|
|
48
|
+
items = []
|
|
49
|
+
find_each { items << it }
|
|
50
|
+
items.each(&)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Iterate through all results from the query, fetching one page at a time
|
|
54
|
+
#
|
|
55
|
+
def find_each(&)
|
|
56
|
+
result = { 'HasNext' => true }
|
|
57
|
+
count = 0
|
|
58
|
+
|
|
59
|
+
while result['HasNext']
|
|
60
|
+
Imis.logger.info 'Fetching IQA Query page'
|
|
61
|
+
|
|
62
|
+
result = fetch
|
|
63
|
+
|
|
64
|
+
count += result['Count'] || 0
|
|
65
|
+
Imis.logger.info " -> #{count} / #{result['TotalCount']} #{'item'.pluralize(count)}"
|
|
66
|
+
Imis.logger.debug ' -> Query page data:'
|
|
67
|
+
JSON.pretty_generate(result).split("\n").each { Imis.logger.debug " -> #{it}" }
|
|
68
|
+
|
|
69
|
+
items = result['Items']['$values'].map { it.except('$type') }
|
|
70
|
+
@offset = result['NextOffset']
|
|
71
|
+
|
|
72
|
+
items.each(&)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def token = api.token
|
|
81
|
+
def token_expiration = api.token_expiration
|
|
82
|
+
|
|
83
|
+
def path = "#{QUERY_PATH}?#{query_params.merge(QueryName: query_name, Offset: offset).to_query}"
|
|
84
|
+
def uri = URI(File.join(Imis.configuration.hostname, path))
|
|
85
|
+
def fetch = JSON.parse(submit(uri, authorize(Net::HTTP::Get.new(uri))).body)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/usps/imis/requests.rb
CHANGED
|
@@ -19,15 +19,29 @@ module Usps
|
|
|
19
19
|
# If the current token is missing/expired, request a new one
|
|
20
20
|
#
|
|
21
21
|
def authorize(request)
|
|
22
|
-
|
|
22
|
+
if token_expiration < Time.now
|
|
23
|
+
Imis.logger.debug 'Token expired: re-authenticating with iMIS'
|
|
24
|
+
authenticate
|
|
25
|
+
end
|
|
23
26
|
request.tap { it.add_field('Authorization', "Bearer #{token}") }
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
def submit(uri, request)
|
|
30
|
+
Imis.logger.info 'Submitting request to iMIS'
|
|
31
|
+
Imis.logger.debug " -> #{uri}"
|
|
32
|
+
sanitized_request_body(request).split("\n").each { Imis.logger.debug " -> #{it}" }
|
|
27
33
|
client(uri).request(request).tap do |result|
|
|
28
34
|
raise Errors::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
|
|
35
|
+
|
|
36
|
+
Imis.logger.info 'Request succeeded'
|
|
29
37
|
end
|
|
30
38
|
end
|
|
39
|
+
|
|
40
|
+
def sanitized_request_body(request)
|
|
41
|
+
return 'grant_type=password&username=[filtered]&password=[filtered]' if request.body&.include?('password=')
|
|
42
|
+
|
|
43
|
+
request.body.nil? ? '*** empty request body ***' : JSON.pretty_generate(JSON.parse(request.body))
|
|
44
|
+
end
|
|
31
45
|
end
|
|
32
46
|
end
|
|
33
47
|
end
|
data/lib/usps/imis/version.rb
CHANGED
data/lib/usps/imis.rb
CHANGED
|
@@ -8,7 +8,9 @@ require 'cgi'
|
|
|
8
8
|
|
|
9
9
|
require 'active_support/core_ext/string/inflections'
|
|
10
10
|
require 'active_support/core_ext/object/to_query'
|
|
11
|
+
require 'active_support/core_ext/enumerable'
|
|
11
12
|
require 'active_support/string_inquirer'
|
|
13
|
+
require 'logger'
|
|
12
14
|
|
|
13
15
|
# Internal requires
|
|
14
16
|
require_relative 'imis/config'
|
|
@@ -39,6 +41,10 @@ module Usps
|
|
|
39
41
|
yield(configuration) if block_given?
|
|
40
42
|
configuration
|
|
41
43
|
end
|
|
44
|
+
|
|
45
|
+
# Logger instance to write to
|
|
46
|
+
#
|
|
47
|
+
def logger = configuration.logger
|
|
42
48
|
end
|
|
43
49
|
end
|
|
44
50
|
end
|
|
@@ -17,13 +17,13 @@ describe Usps::Imis::Api do
|
|
|
17
17
|
it 'stores the initial imis_id' do
|
|
18
18
|
api = described_class.new(imis_id: 42)
|
|
19
19
|
|
|
20
|
-
expect(api.imis_id).to eq(
|
|
20
|
+
expect(api.imis_id).to eq(42)
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
describe '#imis_id_for' do
|
|
25
25
|
it 'gets the iMIS ID' do
|
|
26
|
-
expect(api.imis_id_for('E231625')).to eq(
|
|
26
|
+
expect(api.imis_id_for('E231625')).to eq(31092)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
context 'with a query error' do
|
|
@@ -37,18 +37,18 @@ describe Usps::Imis::Api do
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
describe '#
|
|
40
|
+
describe '#query' do
|
|
41
|
+
let(:query) { api.query('$/ABC/ExampleQueryAll', {}) }
|
|
42
|
+
|
|
41
43
|
before do
|
|
42
|
-
allow(
|
|
44
|
+
allow(query).to receive(:fetch).and_return(
|
|
43
45
|
{ 'Items' => { '$values' => [{ 'key1' => 'value1' }] }, 'HasNext' => true, 'NextOffset' => 1 },
|
|
44
46
|
{ 'Items' => { '$values' => [{ 'key1' => 'value2' }] }, 'HasNext' => false, 'NextOffset' => 0 }
|
|
45
47
|
)
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
it 'collects all query results' do
|
|
49
|
-
expect(
|
|
50
|
-
[{ 'key1' => 'value1' }, { 'key1' => 'value2' }]
|
|
51
|
-
)
|
|
51
|
+
expect(query.to_a).to eq([{ 'key1' => 'value1' }, { 'key1' => 'value2' }])
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
@@ -56,9 +56,7 @@ describe Usps::Imis::Api do
|
|
|
56
56
|
before { api.imis_id = 31092 }
|
|
57
57
|
|
|
58
58
|
it 'sends an update' do
|
|
59
|
-
expect(api.on('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15)).to(
|
|
60
|
-
be_a(Hash)
|
|
61
|
-
)
|
|
59
|
+
expect(api.on('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15)).to be_a(Hash)
|
|
62
60
|
end
|
|
63
61
|
|
|
64
62
|
context 'when receiving a response error' do
|
|
@@ -133,7 +131,7 @@ describe Usps::Imis::Api do
|
|
|
133
131
|
end
|
|
134
132
|
|
|
135
133
|
expect(result).to be_a(Hash)
|
|
136
|
-
expect(api.imis_id).to eq(
|
|
134
|
+
expect(api.imis_id).to eq(31092)
|
|
137
135
|
end
|
|
138
136
|
|
|
139
137
|
it 'nests on and with', :aggregate_failures do
|
|
@@ -22,9 +22,23 @@ describe Usps::Imis::Data do
|
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
describe '#properties' do
|
|
26
|
+
it 'iterates over the properties, excluding IDs' do
|
|
27
|
+
expect(data.properties.map { |field, value| "#{field}: #{value}" }).to eq(
|
|
28
|
+
['Stub Integer: 42', 'Stub String: something']
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'iterates over the properties, including IDs' do
|
|
33
|
+
expect(data.properties(include_ids: true).map { |field, value| "#{field}: #{value}" }).to eq(
|
|
34
|
+
['ID: 31092', 'Stub Integer: 42', 'Stub String: something']
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
25
39
|
describe '#inspect' do
|
|
26
40
|
it 'generates the correct inspect string' do
|
|
27
|
-
expect(data.inspect).to eq('#<Usps::Imis::Data
|
|
41
|
+
expect(data.inspect).to eq('#<Usps::Imis::Data entity="ABC_ASC_Individual_Demog" imis_id=31092>')
|
|
28
42
|
end
|
|
29
43
|
|
|
30
44
|
context 'with data from a Panel' do
|
|
@@ -44,7 +58,7 @@ describe Usps::Imis::Data do
|
|
|
44
58
|
|
|
45
59
|
it 'generates the correct inspect string with an ordinal' do
|
|
46
60
|
expect(data.inspect).to eq(
|
|
47
|
-
'#<Usps::Imis::Data
|
|
61
|
+
'#<Usps::Imis::Data entity="ABC_ASC_Individual_Demog" imis_id=31092 ordinal=99>'
|
|
48
62
|
)
|
|
49
63
|
end
|
|
50
64
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: usps-imis-api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Julian Fiander
|
|
@@ -63,6 +63,7 @@ files:
|
|
|
63
63
|
- lib/usps/imis/panels/education.rb
|
|
64
64
|
- lib/usps/imis/panels/vsc.rb
|
|
65
65
|
- lib/usps/imis/properties.rb
|
|
66
|
+
- lib/usps/imis/query.rb
|
|
66
67
|
- lib/usps/imis/requests.rb
|
|
67
68
|
- lib/usps/imis/version.rb
|
|
68
69
|
- spec/lib/usps/imis/api_spec.rb
|