usps-imis-api 1.0.0.pre.rc.1 → 1.0.0.pre.rc.3
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/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/lib/usps/imis/api.rb +100 -13
- data/lib/usps/imis/config.rb +9 -1
- data/lib/usps/imis/error/api_error.rb +44 -0
- data/lib/usps/imis/error/{mapper.rb → mapper_error.rb} +3 -1
- data/lib/usps/imis/error/{response.rb → response_error.rb} +31 -1
- data/lib/usps/imis/mapper.rb +15 -3
- data/lib/usps/imis/panel/base_panel.rb +23 -2
- data/lib/usps/imis/panel/education.rb +2 -0
- data/lib/usps/imis/panel/vsc.rb +2 -0
- data/lib/usps/imis/version.rb +1 -1
- data/lib/usps/imis.rb +13 -11
- data/spec/lib/usps/imis/api_spec.rb +15 -3
- data/spec/lib/usps/imis/config_spec.rb +1 -1
- data/spec/lib/usps/imis/error/{api_spec.rb → api_error_spec.rb} +1 -1
- data/spec/lib/usps/imis/error/{response_spec.rb → response_error_spec.rb} +4 -4
- data/spec/lib/usps/imis/mapper_spec.rb +1 -1
- data/spec/lib/usps/imis/panel/base_panel_spec.rb +2 -2
- metadata +6 -6
- data/lib/usps/imis/error/api.rb +0 -26
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 927a6d408196ed631d013daac7854beb5b0c27b7b138a454c0078af710cad204
|
|
4
|
+
data.tar.gz: 8d747f8023487b5fa1d2e4fc50a3aa5d26676cc99c818849b6fa9af205a8e50b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b87668b7e37cfa951b729ef0c01b580055b0d48076f6ffab10bff81e0d47ad255df3718e3c63daece6c0a2fc256506eb9ceefec0bed564ce09b1c5bc4e8ba116
|
|
7
|
+
data.tar.gz: e0c08859e7e890887267d13166023ef903355ed70416bd83e856d143de0eab6753d78c0b976acdcc3356144bd3ae92a95ebef43233c6b40a89b17315bb29de0e
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/lib/usps/imis/api.rb
CHANGED
|
@@ -2,14 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
module Usps
|
|
4
4
|
module Imis
|
|
5
|
+
# The core API wrapper
|
|
6
|
+
#
|
|
5
7
|
class Api
|
|
8
|
+
# Endpoint for (re-)authentication requests
|
|
9
|
+
#
|
|
6
10
|
AUTHENTICATION_PATH = 'Token'
|
|
11
|
+
|
|
12
|
+
# Endpoint for general API requests
|
|
13
|
+
#
|
|
7
14
|
API_PATH = 'api'
|
|
15
|
+
|
|
16
|
+
# Endpoint for IQA query requests
|
|
17
|
+
#
|
|
8
18
|
QUERY_PATH = 'api/Query'
|
|
9
|
-
PANELS = Struct.new(:vsc, :education)
|
|
10
19
|
|
|
11
|
-
|
|
20
|
+
# API bearer token
|
|
21
|
+
#
|
|
22
|
+
attr_reader :token
|
|
12
23
|
|
|
24
|
+
# Expiration time for the API bearer token
|
|
25
|
+
#
|
|
26
|
+
# Used to automatically re-authenticate as needed
|
|
27
|
+
#
|
|
28
|
+
attr_reader :token_expiration
|
|
29
|
+
|
|
30
|
+
# Currently selected iMIS ID for API requests
|
|
31
|
+
#
|
|
32
|
+
attr_reader :imis_id
|
|
33
|
+
|
|
34
|
+
# Whether to lock changes to the selected iMIS ID
|
|
35
|
+
#
|
|
36
|
+
attr_reader :lock_imis_id
|
|
37
|
+
|
|
38
|
+
# A new instance of +Api+
|
|
39
|
+
#
|
|
40
|
+
# @param skip_authentication [bool] Skip authentication on initialization (used for tests)
|
|
41
|
+
# @param imis_id [Integer, String] iMIS ID to select immediately on initialization
|
|
42
|
+
#
|
|
13
43
|
def initialize(skip_authentication: false, imis_id: nil)
|
|
14
44
|
authenticate unless skip_authentication
|
|
15
45
|
self.imis_id = imis_id if imis_id
|
|
@@ -17,33 +47,60 @@ module Usps
|
|
|
17
47
|
|
|
18
48
|
# Manually set the current ID, if you already have it for a given member
|
|
19
49
|
#
|
|
50
|
+
# @param id [Integer, String] iMIS ID to select for future requests
|
|
51
|
+
#
|
|
20
52
|
def imis_id=(id)
|
|
53
|
+
raise Error::ApiError, 'Cannot change iMIS ID while locked' if lock_imis_id
|
|
54
|
+
|
|
21
55
|
@imis_id = id.to_i.to_s
|
|
22
56
|
end
|
|
23
57
|
|
|
24
58
|
# Convert a member's certificate number into an iMIS ID number
|
|
25
59
|
#
|
|
60
|
+
# @param certificate [String] Certificate number to lookup the corresponding iMIS ID for
|
|
61
|
+
#
|
|
62
|
+
# @return [String] Corresponding iMIS ID
|
|
63
|
+
#
|
|
26
64
|
def imis_id_for(certificate)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
65
|
+
raise Error::ApiError, 'Cannot change iMIS ID while locked' if lock_imis_id
|
|
66
|
+
|
|
67
|
+
begin
|
|
68
|
+
result = query(Imis.configuration.imis_id_query_name, { certificate: })
|
|
69
|
+
@imis_id = result['Items']['$values'][0]['ID']
|
|
70
|
+
rescue StandardError
|
|
71
|
+
raise Error::ApiError, 'Member not found'
|
|
72
|
+
end
|
|
31
73
|
end
|
|
32
74
|
|
|
33
75
|
# Run requests as DSL, with specific iMIS ID only maintained for this scope
|
|
34
76
|
#
|
|
35
|
-
#
|
|
77
|
+
# While in this block, changes to the value of +imis_id+ are not allowed
|
|
78
|
+
#
|
|
79
|
+
# @param id [Integer, String] iMIS ID to select for requests within the block
|
|
80
|
+
#
|
|
81
|
+
# @example
|
|
82
|
+
# with(12345) do
|
|
83
|
+
# update(mm: 15)
|
|
84
|
+
# end
|
|
36
85
|
#
|
|
37
86
|
def with(id, &)
|
|
38
87
|
old_id = imis_id
|
|
39
88
|
self.imis_id = id
|
|
89
|
+
|
|
90
|
+
@lock_imis_id = true
|
|
40
91
|
instance_eval(&)
|
|
41
92
|
ensure
|
|
93
|
+
@lock_imis_id = false
|
|
42
94
|
self.imis_id = old_id
|
|
43
95
|
end
|
|
44
96
|
|
|
45
97
|
# Get a business object for the current member
|
|
46
98
|
#
|
|
99
|
+
# @param business_object_name [String] Name of the business object
|
|
100
|
+
# @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
|
|
101
|
+
#
|
|
102
|
+
# @return [Hash] Response data from the API
|
|
103
|
+
#
|
|
47
104
|
def get(business_object_name, url_id: nil)
|
|
48
105
|
uri = uri_for(business_object_name, url_id:)
|
|
49
106
|
request = Net::HTTP::Get.new(uri)
|
|
@@ -53,7 +110,11 @@ module Usps
|
|
|
53
110
|
|
|
54
111
|
# Update only specific fields on a business object for the current member
|
|
55
112
|
#
|
|
56
|
-
#
|
|
113
|
+
# @param business_object_name [String] Name of the business object
|
|
114
|
+
# @param fields [Hash] Conforms to pattern +{ field_key => value }+
|
|
115
|
+
# @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
|
|
116
|
+
#
|
|
117
|
+
# @return [Hash] Response data from the API
|
|
57
118
|
#
|
|
58
119
|
def put_fields(business_object_name, fields, url_id: nil)
|
|
59
120
|
updated = filter_fields(business_object_name, fields)
|
|
@@ -62,6 +123,12 @@ module Usps
|
|
|
62
123
|
|
|
63
124
|
# Update a business object for the current member
|
|
64
125
|
#
|
|
126
|
+
# @param business_object_name [String] Name of the business object
|
|
127
|
+
# @param body [Hash] Full raw API object data
|
|
128
|
+
# @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
|
|
129
|
+
#
|
|
130
|
+
# @return [Hash] Response data from the API
|
|
131
|
+
#
|
|
65
132
|
def put(business_object_name, body, url_id: nil)
|
|
66
133
|
uri = uri_for(business_object_name, url_id:)
|
|
67
134
|
request = Net::HTTP::Put.new(uri)
|
|
@@ -72,6 +139,12 @@ module Usps
|
|
|
72
139
|
|
|
73
140
|
# Create a business object for the current member
|
|
74
141
|
#
|
|
142
|
+
# @param business_object_name [String] Name of the business object
|
|
143
|
+
# @param body [Hash] Full raw API object data
|
|
144
|
+
# @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
|
|
145
|
+
#
|
|
146
|
+
# @return [Hash] Response data from the API
|
|
147
|
+
#
|
|
75
148
|
def post(business_object_name, body, url_id: nil)
|
|
76
149
|
uri = uri_for(business_object_name, url_id:)
|
|
77
150
|
request = Net::HTTP::Post.new(uri)
|
|
@@ -82,7 +155,10 @@ module Usps
|
|
|
82
155
|
|
|
83
156
|
# Remove a business object for the current member
|
|
84
157
|
#
|
|
85
|
-
#
|
|
158
|
+
# @param business_object_name [String] Name of the business object
|
|
159
|
+
# @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
|
|
160
|
+
#
|
|
161
|
+
# @return [String] Error response body from the API, or empty string on success
|
|
86
162
|
#
|
|
87
163
|
def delete(business_object_name, url_id: nil)
|
|
88
164
|
uri = uri_for(business_object_name, url_id:)
|
|
@@ -93,8 +169,10 @@ module Usps
|
|
|
93
169
|
|
|
94
170
|
# Run an IQA Query
|
|
95
171
|
#
|
|
96
|
-
#
|
|
97
|
-
#
|
|
172
|
+
# @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
|
|
173
|
+
# @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
|
|
174
|
+
#
|
|
175
|
+
# @return [Hash] Response data from the API
|
|
98
176
|
#
|
|
99
177
|
def query(query_name, query_params = {})
|
|
100
178
|
query_params[:QueryName] = query_name
|
|
@@ -105,21 +183,30 @@ module Usps
|
|
|
105
183
|
JSON.parse(result.body)
|
|
106
184
|
end
|
|
107
185
|
|
|
186
|
+
# An instance of Mapper, using this instance as its parent +Api+
|
|
187
|
+
#
|
|
108
188
|
def mapper
|
|
109
189
|
@mapper ||= Mapper.new(self)
|
|
110
190
|
end
|
|
111
191
|
|
|
192
|
+
# Convenience accessor for available Panel objects, each using this instance as its parent
|
|
193
|
+
# +Api+
|
|
194
|
+
#
|
|
112
195
|
def panels
|
|
113
|
-
@panels ||=
|
|
196
|
+
@panels ||= Struct.new(:vsc, :education).new(
|
|
114
197
|
Panel::Vsc.new(self),
|
|
115
198
|
Panel::Education.new(self)
|
|
116
199
|
)
|
|
117
200
|
end
|
|
118
201
|
|
|
202
|
+
# Convenience alias for updating mapped fields
|
|
203
|
+
#
|
|
119
204
|
def update(data)
|
|
120
205
|
mapper.update(data)
|
|
121
206
|
end
|
|
122
207
|
|
|
208
|
+
# Ruby 3.5 instance variable filter
|
|
209
|
+
#
|
|
123
210
|
def instance_variables_to_inspect = %i[@token_expiration @imis_id]
|
|
124
211
|
|
|
125
212
|
private
|
|
@@ -154,7 +241,7 @@ module Usps
|
|
|
154
241
|
|
|
155
242
|
def submit(uri, request)
|
|
156
243
|
client(uri).request(request).tap do |result|
|
|
157
|
-
raise Error::
|
|
244
|
+
raise Error::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
|
|
158
245
|
end
|
|
159
246
|
end
|
|
160
247
|
|
data/lib/usps/imis/config.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Usps
|
|
4
4
|
module Imis
|
|
5
|
+
# API Configuration
|
|
6
|
+
#
|
|
5
7
|
class Config
|
|
6
8
|
IMIS_ROOT_URL_PROD = 'https://portal.americasboatingclub.org'
|
|
7
9
|
IMIS_ROOT_URL_DEV = 'https://abcdev.imiscloud.com'
|
|
@@ -12,6 +14,10 @@ module Usps
|
|
|
12
14
|
yield self if block_given?
|
|
13
15
|
end
|
|
14
16
|
|
|
17
|
+
# Environment-specific API endpoint hostname
|
|
18
|
+
#
|
|
19
|
+
# @return The API hostname for the current environment
|
|
20
|
+
#
|
|
15
21
|
def hostname
|
|
16
22
|
case environment.to_sym
|
|
17
23
|
when :production
|
|
@@ -19,10 +25,12 @@ module Usps
|
|
|
19
25
|
when :development
|
|
20
26
|
IMIS_ROOT_URL_DEV
|
|
21
27
|
else
|
|
22
|
-
raise Error::
|
|
28
|
+
raise Error::ApiError, "Unexpected API environment: #{environment}"
|
|
23
29
|
end
|
|
24
30
|
end
|
|
25
31
|
|
|
32
|
+
# Ruby 3.5 instance variable filter
|
|
33
|
+
#
|
|
26
34
|
def instance_variables_to_inspect = %i[@environment @imis_id_query_name @username]
|
|
27
35
|
end
|
|
28
36
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Usps
|
|
4
|
+
module Imis
|
|
5
|
+
module Error
|
|
6
|
+
# Base error class for all internal exceptions
|
|
7
|
+
#
|
|
8
|
+
class ApiError < StandardError
|
|
9
|
+
# Additional call-specific metadata to pass through to Bugsnag
|
|
10
|
+
#
|
|
11
|
+
attr_accessor :metadata
|
|
12
|
+
|
|
13
|
+
# A new instance of +ApiError+
|
|
14
|
+
#
|
|
15
|
+
# @param message [String] The base exception message
|
|
16
|
+
# @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
|
|
17
|
+
#
|
|
18
|
+
def initialize(message, metadata = {})
|
|
19
|
+
super(message)
|
|
20
|
+
@metadata = metadata
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Additional metadata to include in Bugsnag reports
|
|
24
|
+
#
|
|
25
|
+
# Can include fields at the top level, which will be shows on the custom tab
|
|
26
|
+
#
|
|
27
|
+
# Can include fields nested under a top-level key, which will be shown on a tab with the
|
|
28
|
+
# top-level key as its name
|
|
29
|
+
#
|
|
30
|
+
# @return [Hash]
|
|
31
|
+
#
|
|
32
|
+
def bugsnag_meta_data
|
|
33
|
+
metadata == {} ? {} : base_metadata
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def base_metadata
|
|
39
|
+
{ api: metadata }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -3,23 +3,53 @@
|
|
|
3
3
|
module Usps
|
|
4
4
|
module Imis
|
|
5
5
|
module Error
|
|
6
|
-
|
|
6
|
+
# Exception raised due to receiving an error response from the API
|
|
7
|
+
#
|
|
8
|
+
class ResponseError < ApiError
|
|
9
|
+
# [Net::HTTPResponse] The response received from the API
|
|
10
|
+
#
|
|
7
11
|
attr_reader :response
|
|
12
|
+
|
|
13
|
+
# [Hash] Additional call-specific metadata to pass through to Bugsnag
|
|
14
|
+
#
|
|
8
15
|
attr_accessor :metadata
|
|
9
16
|
|
|
17
|
+
# Create a new instance of +ResponseError+ from an API response
|
|
18
|
+
#
|
|
19
|
+
# @param response [Net::HTTPResponse] The response received from the API
|
|
20
|
+
#
|
|
10
21
|
def self.from(response)
|
|
11
22
|
new(nil, response)
|
|
12
23
|
end
|
|
13
24
|
|
|
25
|
+
# Create a new instance of +ResponseError+
|
|
26
|
+
#
|
|
27
|
+
# @param _message Ignored
|
|
28
|
+
# @param response [Net::HTTPResponse] The response received from the API
|
|
29
|
+
# @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
|
|
30
|
+
#
|
|
14
31
|
def initialize(_message, response, metadata = {})
|
|
15
32
|
@response = response
|
|
16
33
|
super(message, metadata)
|
|
17
34
|
end
|
|
18
35
|
|
|
36
|
+
# Additional metadata to include in Bugsnag reports
|
|
37
|
+
#
|
|
38
|
+
# Can include fields at the top level, which will be shows on the +custom+ tab
|
|
39
|
+
#
|
|
40
|
+
# Can include fields nested under a top-level key, which will be shown on a tab with the
|
|
41
|
+
# top-level key as its name
|
|
42
|
+
#
|
|
43
|
+
# @return [Hash]
|
|
44
|
+
#
|
|
19
45
|
def bugsnag_meta_data
|
|
20
46
|
base_metadata.tap { |m| m[:api].merge!(metadata) }
|
|
21
47
|
end
|
|
22
48
|
|
|
49
|
+
# Auto-formatted exception message, based on the provided API response
|
|
50
|
+
#
|
|
51
|
+
# @return [String] The exception message
|
|
52
|
+
#
|
|
23
53
|
def message
|
|
24
54
|
[
|
|
25
55
|
"#{self.class.name}: [#{status.to_s.upcase}] The iMIS API returned an error.",
|
data/lib/usps/imis/mapper.rb
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Usps
|
|
4
4
|
module Imis
|
|
5
|
+
# Specific known fields mapping to facilitate updating across multiple
|
|
6
|
+
# business objects.
|
|
7
|
+
#
|
|
5
8
|
class Mapper
|
|
9
|
+
# List of known mapped fields
|
|
10
|
+
#
|
|
6
11
|
FIELD_MAPPING = {
|
|
7
12
|
grade: %w[ABC_ASC_Individual_Demog Grade],
|
|
8
13
|
edpro: %w[ABC_ASC_Individual_Demog Educ_Proficiency],
|
|
@@ -12,19 +17,26 @@ module Usps
|
|
|
12
17
|
mm_updated: %w[ABC_ASC_Individual_Demog MMS_Updated]
|
|
13
18
|
}.freeze
|
|
14
19
|
|
|
20
|
+
# The parent +Api+ object
|
|
21
|
+
#
|
|
15
22
|
attr_reader :api
|
|
16
23
|
|
|
24
|
+
# A new instance of +Mapper+
|
|
25
|
+
#
|
|
17
26
|
def initialize(api = nil, imis_id: nil)
|
|
18
27
|
@api = api || Api.new
|
|
19
28
|
@api.imis_id = imis_id if imis_id
|
|
20
29
|
end
|
|
21
30
|
|
|
22
31
|
# Update a member's data on multiple affected business objects by arbitrary field names
|
|
32
|
+
#
|
|
23
33
|
# Does not require knowing which business object / iMIS-specific field name to use
|
|
24
34
|
#
|
|
25
|
-
# Only available for
|
|
35
|
+
# Only available for fields defined in +FIELD_MAPPING+
|
|
36
|
+
#
|
|
37
|
+
# @param data [Hash] Conforms to pattern +{ field_key => value }+
|
|
26
38
|
#
|
|
27
|
-
#
|
|
39
|
+
# @return [Array<Hash>] Response data from the API for each internal update request
|
|
28
40
|
#
|
|
29
41
|
def update(data)
|
|
30
42
|
updates = data.each_with_object({}) do |(field_key, value), hash|
|
|
@@ -62,7 +74,7 @@ module Usps
|
|
|
62
74
|
end
|
|
63
75
|
|
|
64
76
|
raise(
|
|
65
|
-
Error::
|
|
77
|
+
Error::MapperError,
|
|
66
78
|
"Unrecognized field: \"#{field_name}\". " \
|
|
67
79
|
'Please report what data you are attempting to work with to ITCom leadership.'
|
|
68
80
|
)
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
module Usps
|
|
4
4
|
module Imis
|
|
5
5
|
module Panel
|
|
6
|
+
# Base class for configuring Panels
|
|
7
|
+
#
|
|
6
8
|
class BasePanel
|
|
9
|
+
# The parent +Api+ object
|
|
10
|
+
#
|
|
7
11
|
attr_reader :api
|
|
8
12
|
|
|
9
13
|
def initialize(api = nil, imis_id: nil)
|
|
@@ -11,18 +15,35 @@ module Usps
|
|
|
11
15
|
@api.imis_id = imis_id if imis_id
|
|
12
16
|
end
|
|
13
17
|
|
|
18
|
+
# Get a specific object from the Panel
|
|
19
|
+
#
|
|
20
|
+
# @param ordinal [Integer] The ordinal identifier for the desired object
|
|
21
|
+
#
|
|
14
22
|
def get(ordinal)
|
|
15
23
|
api.get(business_object, url_id: "~#{api.imis_id}|#{ordinal}")
|
|
16
24
|
end
|
|
17
25
|
|
|
26
|
+
# Create a new object in the Panel
|
|
27
|
+
#
|
|
28
|
+
# @param data [Hash] The record data for the desired object
|
|
29
|
+
#
|
|
18
30
|
def create(data)
|
|
19
31
|
api.post(business_object, payload(data), url_id: '')
|
|
20
32
|
end
|
|
21
33
|
|
|
34
|
+
# Update an existing object in the Panel
|
|
35
|
+
#
|
|
36
|
+
# @param data [Hash] The record data for the desired object -- including the required
|
|
37
|
+
# +ordinal+ identifier
|
|
38
|
+
#
|
|
22
39
|
def update(data)
|
|
23
40
|
api.put(business_object, payload(data), url_id: "~#{api.imis_id}|#{data[:ordinal]}")
|
|
24
41
|
end
|
|
25
42
|
|
|
43
|
+
# Remove a specific object from the Panel
|
|
44
|
+
#
|
|
45
|
+
# @param ordinal [Integer] The ordinal identifier for the desired object
|
|
46
|
+
#
|
|
26
47
|
def destroy(ordinal)
|
|
27
48
|
api.delete(business_object, url_id: "~#{api.imis_id}|#{ordinal}")
|
|
28
49
|
end
|
|
@@ -30,11 +51,11 @@ module Usps
|
|
|
30
51
|
private
|
|
31
52
|
|
|
32
53
|
def business_object
|
|
33
|
-
raise Error::
|
|
54
|
+
raise Error::ApiError, "#{self.class.name} must implement #business_object"
|
|
34
55
|
end
|
|
35
56
|
|
|
36
57
|
def payload(_data)
|
|
37
|
-
raise Error::
|
|
58
|
+
raise Error::ApiError, "#{self.class.name} must implement #payload(data)"
|
|
38
59
|
end
|
|
39
60
|
end
|
|
40
61
|
end
|
data/lib/usps/imis/panel/vsc.rb
CHANGED
data/lib/usps/imis/version.rb
CHANGED
data/lib/usps/imis.rb
CHANGED
|
@@ -13,9 +13,9 @@ require 'ext/hash' unless defined?(Rails)
|
|
|
13
13
|
|
|
14
14
|
# Internal requires
|
|
15
15
|
require_relative 'imis/config'
|
|
16
|
-
require_relative 'imis/error/
|
|
17
|
-
require_relative 'imis/error/
|
|
18
|
-
require_relative 'imis/error/
|
|
16
|
+
require_relative 'imis/error/api_error'
|
|
17
|
+
require_relative 'imis/error/mapper_error'
|
|
18
|
+
require_relative 'imis/error/response_error'
|
|
19
19
|
require_relative 'imis/api'
|
|
20
20
|
require_relative 'imis/mapper'
|
|
21
21
|
require_relative 'imis/panel/base_panel'
|
|
@@ -23,24 +23,26 @@ require_relative 'imis/panel/vsc'
|
|
|
23
23
|
require_relative 'imis/panel/education'
|
|
24
24
|
|
|
25
25
|
module Usps
|
|
26
|
+
# API wrapper for interacting with iMIS
|
|
27
|
+
#
|
|
26
28
|
module Imis
|
|
27
29
|
class << self
|
|
30
|
+
# Accessor for configuration values
|
|
31
|
+
#
|
|
32
|
+
# @return The configuration object
|
|
33
|
+
#
|
|
28
34
|
def configuration
|
|
29
35
|
@configuration ||= Config.new
|
|
30
36
|
end
|
|
31
37
|
|
|
38
|
+
# Used to define a block of configuration settings
|
|
39
|
+
#
|
|
40
|
+
# @return The updated configuration object
|
|
41
|
+
#
|
|
32
42
|
def configure
|
|
33
43
|
yield(configuration) if block_given?
|
|
34
44
|
configuration
|
|
35
45
|
end
|
|
36
|
-
|
|
37
|
-
# def mock!(value = true)
|
|
38
|
-
# @mock = value
|
|
39
|
-
# end
|
|
40
|
-
|
|
41
|
-
# def mock
|
|
42
|
-
# @mock || false
|
|
43
|
-
# end
|
|
44
46
|
end
|
|
45
47
|
end
|
|
46
48
|
end
|
|
@@ -31,7 +31,7 @@ describe Usps::Imis::Api do
|
|
|
31
31
|
|
|
32
32
|
it 'wraps errors' do
|
|
33
33
|
expect { api.imis_id_for('E231625') }.to raise_error(
|
|
34
|
-
Usps::Imis::Error::
|
|
34
|
+
Usps::Imis::Error::ApiError, 'Member not found'
|
|
35
35
|
)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -47,7 +47,7 @@ describe Usps::Imis::Api do
|
|
|
47
47
|
context 'when receiving a response error' do
|
|
48
48
|
let(:warning_text) do
|
|
49
49
|
<<~WARNING.chomp
|
|
50
|
-
Usps::Imis::Error::
|
|
50
|
+
Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
|
|
51
51
|
Something went wrong
|
|
52
52
|
WARNING
|
|
53
53
|
end
|
|
@@ -62,7 +62,7 @@ describe Usps::Imis::Api do
|
|
|
62
62
|
|
|
63
63
|
it 'wraps the error' do
|
|
64
64
|
expect { api.put_fields('ABC_ASC_Individual_Demog', { 'TotMMS' => 15 }) }.to raise_error(
|
|
65
|
-
Usps::Imis::Error::
|
|
65
|
+
Usps::Imis::Error::ApiError, warning_text
|
|
66
66
|
)
|
|
67
67
|
end
|
|
68
68
|
end
|
|
@@ -82,6 +82,18 @@ describe Usps::Imis::Api do
|
|
|
82
82
|
it 'uses a panel correctly' do
|
|
83
83
|
expect(api.with(6374) { panels.vsc.get(1433) }).to be_a(Hash)
|
|
84
84
|
end
|
|
85
|
+
|
|
86
|
+
it 'blocks calling imis_id=' do
|
|
87
|
+
expect do
|
|
88
|
+
api.with(31092) { self.imis_id = 31092 }
|
|
89
|
+
end.to raise_error(Usps::Imis::Error::ApiError, 'Cannot change iMIS ID while locked')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'blocks calling imis_id_for' do
|
|
93
|
+
expect do
|
|
94
|
+
api.with(31092) { imis_id_for('E231625') }
|
|
95
|
+
end.to raise_error(Usps::Imis::Error::ApiError, 'Cannot change iMIS ID while locked')
|
|
96
|
+
end
|
|
85
97
|
end
|
|
86
98
|
|
|
87
99
|
describe '#inspect' do
|
|
@@ -25,7 +25,7 @@ describe Usps::Imis::Config do
|
|
|
25
25
|
|
|
26
26
|
it 'raises an error' do
|
|
27
27
|
expect { config.hostname }.to raise_error(
|
|
28
|
-
Usps::Imis::Error::
|
|
28
|
+
Usps::Imis::Error::ApiError, 'Unexpected API environment: nothing'
|
|
29
29
|
)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
@@ -4,7 +4,7 @@ require 'spec_helper'
|
|
|
4
4
|
|
|
5
5
|
ApiResponseStub = Struct.new(:code, :body)
|
|
6
6
|
|
|
7
|
-
describe Usps::Imis::Error::
|
|
7
|
+
describe Usps::Imis::Error::ResponseError do
|
|
8
8
|
let(:error) { described_class.from(response) }
|
|
9
9
|
|
|
10
10
|
describe 'error codes' do
|
|
@@ -61,7 +61,7 @@ describe Usps::Imis::Error::Response do
|
|
|
61
61
|
let(:response) { ApiResponseStub.new('500', 'Body of the API response error') }
|
|
62
62
|
let(:warning_text) do
|
|
63
63
|
<<~WARNING.chomp
|
|
64
|
-
Usps::Imis::Error::
|
|
64
|
+
Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
|
|
65
65
|
Body of the API response error
|
|
66
66
|
WARNING
|
|
67
67
|
end
|
|
@@ -78,7 +78,7 @@ describe Usps::Imis::Error::Response do
|
|
|
78
78
|
let(:response) { ApiResponseStub.new('500', response_body) }
|
|
79
79
|
let(:warning_text) do
|
|
80
80
|
<<~WARNING.chomp
|
|
81
|
-
Usps::Imis::Error::
|
|
81
|
+
Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
|
|
82
82
|
description
|
|
83
83
|
WARNING
|
|
84
84
|
end
|
|
@@ -95,7 +95,7 @@ describe Usps::Imis::Error::Response do
|
|
|
95
95
|
let(:response) { ApiResponseStub.new('500', response_body) }
|
|
96
96
|
let(:warning_text) do
|
|
97
97
|
<<~WARNING.chomp
|
|
98
|
-
Usps::Imis::Error::
|
|
98
|
+
Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
|
|
99
99
|
#{response_body}
|
|
100
100
|
WARNING
|
|
101
101
|
end
|
|
@@ -22,7 +22,7 @@ describe Usps::Imis::Mapper do
|
|
|
22
22
|
|
|
23
23
|
it 'raises for unmapped updates' do
|
|
24
24
|
expect { api.mapper.update(something: 'anything') }.to raise_error(
|
|
25
|
-
Usps::Imis::Error::
|
|
25
|
+
Usps::Imis::Error::MapperError,
|
|
26
26
|
'Unrecognized field: "something". ' \
|
|
27
27
|
'Please report what data you are attempting to work with to ITCom leadership.'
|
|
28
28
|
)
|
|
@@ -19,13 +19,13 @@ end
|
|
|
19
19
|
describe Usps::Imis::Panel::BasePanel do
|
|
20
20
|
it 'requires #business_object to be defined' do
|
|
21
21
|
expect { Usps::Imis::Panel::InvalidPanel.new.get(1) }.to raise_error(
|
|
22
|
-
Usps::Imis::Error::
|
|
22
|
+
Usps::Imis::Error::ApiError, 'Usps::Imis::Panel::InvalidPanel must implement #business_object'
|
|
23
23
|
)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
it 'requires #payload(data) to be defined' do
|
|
27
27
|
expect { Usps::Imis::Panel::InvalidPanelWithBusinessObject.new.create({}) }.to raise_error(
|
|
28
|
-
Usps::Imis::Error::
|
|
28
|
+
Usps::Imis::Error::ApiError,
|
|
29
29
|
'Usps::Imis::Panel::InvalidPanelWithBusinessObject must implement #payload(data)'
|
|
30
30
|
)
|
|
31
31
|
end
|
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: 1.0.0.pre.rc.
|
|
4
|
+
version: 1.0.0.pre.rc.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Julian Fiander
|
|
@@ -31,9 +31,9 @@ files:
|
|
|
31
31
|
- lib/usps/imis.rb
|
|
32
32
|
- lib/usps/imis/api.rb
|
|
33
33
|
- lib/usps/imis/config.rb
|
|
34
|
-
- lib/usps/imis/error/
|
|
35
|
-
- lib/usps/imis/error/
|
|
36
|
-
- lib/usps/imis/error/
|
|
34
|
+
- lib/usps/imis/error/api_error.rb
|
|
35
|
+
- lib/usps/imis/error/mapper_error.rb
|
|
36
|
+
- lib/usps/imis/error/response_error.rb
|
|
37
37
|
- lib/usps/imis/mapper.rb
|
|
38
38
|
- lib/usps/imis/panel/base_panel.rb
|
|
39
39
|
- lib/usps/imis/panel/education.rb
|
|
@@ -41,8 +41,8 @@ files:
|
|
|
41
41
|
- lib/usps/imis/version.rb
|
|
42
42
|
- spec/lib/usps/imis/api_spec.rb
|
|
43
43
|
- spec/lib/usps/imis/config_spec.rb
|
|
44
|
-
- spec/lib/usps/imis/error/
|
|
45
|
-
- spec/lib/usps/imis/error/
|
|
44
|
+
- spec/lib/usps/imis/error/api_error_spec.rb
|
|
45
|
+
- spec/lib/usps/imis/error/response_error_spec.rb
|
|
46
46
|
- spec/lib/usps/imis/mapper_spec.rb
|
|
47
47
|
- spec/lib/usps/imis/panel/base_panel_spec.rb
|
|
48
48
|
- spec/lib/usps/imis/panel/education_spec.rb
|
data/lib/usps/imis/error/api.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Usps
|
|
4
|
-
module Imis
|
|
5
|
-
module Error
|
|
6
|
-
class Api < StandardError
|
|
7
|
-
attr_accessor :metadata
|
|
8
|
-
|
|
9
|
-
def initialize(message, metadata = {})
|
|
10
|
-
super(message)
|
|
11
|
-
@metadata = metadata
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def bugsnag_meta_data
|
|
15
|
-
metadata == {} ? {} : base_metadata
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
def base_metadata
|
|
21
|
-
{ api: metadata }
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|