usps-imis-api 1.0.0.pre.rc.1 → 1.0.0.pre.rc.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 591c0f59f5d39e06c011116940615588936cef78dfb8e497670909d5654c61b8
4
- data.tar.gz: 2f667e0e06d05a519bff31e6387452dc896aa4204443ceb3ae43d1dab8f2eaf0
3
+ metadata.gz: bd103cb82cf705d717bd293bef46390aee8a82dca66ec103fa28510bb67b921c
4
+ data.tar.gz: 4d1dee0de5129874d612b8b888d57b24918582925b61ffac91ef7722a5cbc9cd
5
5
  SHA512:
6
- metadata.gz: 622f9629c46f876901542639099e7544d28d932121e7a9bd09513fcdb0c756e2727f6b69aad8ead5606dd36803a80d9f66f2e2c5e4e6cc08fe7133fc799023de
7
- data.tar.gz: 07ffc1e12820b524083e68d054e23eb976fcd7a16cf48fdbf7d64fe25a5d75b4083e2e6aafd7e6a19671ecaa9a7e2b33240a7bd4aa6d487f4f83fb14316c5aae
6
+ metadata.gz: 30acc54f0082681a9c38ba36bdfe6252331a0199416e131557352a880df66b465cd30de07fb3c3ab0d66366df97b096210e58be649387a3929609c09b9293010
7
+ data.tar.gz: 729b191b9d78e62f0acc659730d3761e4dc8a60f72304dd5b584a6ac9a63853c659c0fc335ceb7cbd35d903bc2c85656c0642259b2ee8c2f318669741d0d31fe
data/.gitignore CHANGED
@@ -2,3 +2,4 @@ coverage/
2
2
  tmp/
3
3
  .env
4
4
  *.gem
5
+ .yardoc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- usps-imis-api (1.0.0.pre.rc.1)
4
+ usps-imis-api (1.0.0.pre.rc.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/lib/usps/imis/api.rb CHANGED
@@ -2,14 +2,40 @@
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
- attr_reader :token, :token_expiration, :imis_id
20
+ # API bearer token
21
+ #
22
+ attr_reader :token
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
12
33
 
34
+ # A new instance of +Api+
35
+ #
36
+ # @param skip_authentication [bool] Skip authentication on initialization (used for tests)
37
+ # @param imis_id [Integer, String] iMIS ID to select immediately on initialization
38
+ #
13
39
  def initialize(skip_authentication: false, imis_id: nil)
14
40
  authenticate unless skip_authentication
15
41
  self.imis_id = imis_id if imis_id
@@ -17,12 +43,18 @@ module Usps
17
43
 
18
44
  # Manually set the current ID, if you already have it for a given member
19
45
  #
46
+ # @param id [Integer, String] iMIS ID to select for future requests
47
+ #
20
48
  def imis_id=(id)
21
49
  @imis_id = id.to_i.to_s
22
50
  end
23
51
 
24
52
  # Convert a member's certificate number into an iMIS ID number
25
53
  #
54
+ # @param certificate [String] Certificate number to lookup the corresponding iMIS ID for
55
+ #
56
+ # @return [String] Corresponding iMIS ID
57
+ #
26
58
  def imis_id_for(certificate)
27
59
  result = query(Imis.configuration.imis_id_query_name, { certificate: })
28
60
  @imis_id = result['Items']['$values'][0]['ID']
@@ -34,6 +66,13 @@ module Usps
34
66
  #
35
67
  # This should be used with methods that do not change the value of `imis_id`
36
68
  #
69
+ # @param id [Integer, String] iMIS ID to select for requests within the block
70
+ #
71
+ # @example
72
+ # with(12345) do
73
+ # update(mm: 15)
74
+ # end
75
+ #
37
76
  def with(id, &)
38
77
  old_id = imis_id
39
78
  self.imis_id = id
@@ -44,6 +83,11 @@ module Usps
44
83
 
45
84
  # Get a business object for the current member
46
85
  #
86
+ # @param business_object_name [String] Name of the business object
87
+ # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
88
+ #
89
+ # @return [Hash] Response data from the API
90
+ #
47
91
  def get(business_object_name, url_id: nil)
48
92
  uri = uri_for(business_object_name, url_id:)
49
93
  request = Net::HTTP::Get.new(uri)
@@ -53,7 +97,11 @@ module Usps
53
97
 
54
98
  # Update only specific fields on a business object for the current member
55
99
  #
56
- # fields - hash of shape: { field_name => new_value }
100
+ # @param business_object_name [String] Name of the business object
101
+ # @param fields [Hash] Conforms to pattern +{ field_key => value }+
102
+ # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
103
+ #
104
+ # @return [Hash] Response data from the API
57
105
  #
58
106
  def put_fields(business_object_name, fields, url_id: nil)
59
107
  updated = filter_fields(business_object_name, fields)
@@ -62,6 +110,12 @@ module Usps
62
110
 
63
111
  # Update a business object for the current member
64
112
  #
113
+ # @param business_object_name [String] Name of the business object
114
+ # @param body [Hash] Full raw API object data
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
118
+ #
65
119
  def put(business_object_name, body, url_id: nil)
66
120
  uri = uri_for(business_object_name, url_id:)
67
121
  request = Net::HTTP::Put.new(uri)
@@ -72,6 +126,12 @@ module Usps
72
126
 
73
127
  # Create a business object for the current member
74
128
  #
129
+ # @param business_object_name [String] Name of the business object
130
+ # @param body [Hash] Full raw API object data
131
+ # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
132
+ #
133
+ # @return [Hash] Response data from the API
134
+ #
75
135
  def post(business_object_name, body, url_id: nil)
76
136
  uri = uri_for(business_object_name, url_id:)
77
137
  request = Net::HTTP::Post.new(uri)
@@ -82,7 +142,10 @@ module Usps
82
142
 
83
143
  # Remove a business object for the current member
84
144
  #
85
- # Returns empty string on success
145
+ # @param business_object_name [String] Name of the business object
146
+ # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
147
+ #
148
+ # @return [String] Error response body from the API, or empty string on success
86
149
  #
87
150
  def delete(business_object_name, url_id: nil)
88
151
  uri = uri_for(business_object_name, url_id:)
@@ -93,8 +156,10 @@ module Usps
93
156
 
94
157
  # Run an IQA Query
95
158
  #
96
- # query_name - the full path of the query in IQA, e.g. `$/_ABC/Fiander/iMIS_ID`
97
- # query_params - hash of shape: { param_name => param_value }
159
+ # @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
160
+ # @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
161
+ #
162
+ # @return [Hash] Response data from the API
98
163
  #
99
164
  def query(query_name, query_params = {})
100
165
  query_params[:QueryName] = query_name
@@ -105,21 +170,30 @@ module Usps
105
170
  JSON.parse(result.body)
106
171
  end
107
172
 
173
+ # An instance of Mapper, using this instance as its parent +Api+
174
+ #
108
175
  def mapper
109
176
  @mapper ||= Mapper.new(self)
110
177
  end
111
178
 
179
+ # Convenience accessor for available Panel objects, each using this instance as its parent
180
+ # +Api+
181
+ #
112
182
  def panels
113
- @panels ||= PANELS.new(
183
+ @panels ||= Struct.new(:vsc, :education).new(
114
184
  Panel::Vsc.new(self),
115
185
  Panel::Education.new(self)
116
186
  )
117
187
  end
118
188
 
189
+ # Convenience alias for updating mapped fields
190
+ #
119
191
  def update(data)
120
192
  mapper.update(data)
121
193
  end
122
194
 
195
+ # Ruby 3.5 instance variable filter
196
+ #
123
197
  def instance_variables_to_inspect = %i[@token_expiration @imis_id]
124
198
 
125
199
  private
@@ -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
@@ -23,6 +29,8 @@ module Usps
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
@@ -3,14 +3,32 @@
3
3
  module Usps
4
4
  module Imis
5
5
  module Error
6
+ # Base error class for all internal exceptions
7
+ #
6
8
  class Api < StandardError
9
+ # Additional call-specific metadata to pass through to Bugsnag
10
+ #
7
11
  attr_accessor :metadata
8
12
 
13
+ # A new instance of +Error::Api+
14
+ #
15
+ # @param message [String] The base exception message
16
+ # @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
17
+ #
9
18
  def initialize(message, metadata = {})
10
19
  super(message)
11
20
  @metadata = metadata
12
21
  end
13
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
+ #
14
32
  def bugsnag_meta_data
15
33
  metadata == {} ? {} : base_metadata
16
34
  end
@@ -3,6 +3,8 @@
3
3
  module Usps
4
4
  module Imis
5
5
  module Error
6
+ # Exception raised by a +Mapper+
7
+ #
6
8
  class Mapper < Api; end
7
9
  end
8
10
  end
@@ -3,23 +3,53 @@
3
3
  module Usps
4
4
  module Imis
5
5
  module Error
6
+ # Exception raised due to receiving an error response from the API
7
+ #
6
8
  class Response < Api
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 +Error::Response+ 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 +Error::Response+
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.",
@@ -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 previously-mapped fields
35
+ # Only available for fields defined in +FIELD_MAPPING+
36
+ #
37
+ # @param data [Hash] Conforms to pattern +{ field_key => value }+
26
38
  #
27
- # `data` is a hash of shape { field_key => value }
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|
@@ -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
@@ -3,6 +3,8 @@
3
3
  module Usps
4
4
  module Imis
5
5
  module Panel
6
+ # Panel for accessing the Educational completions business object
7
+ #
6
8
  class Education < BasePanel
7
9
  private
8
10
 
@@ -3,6 +3,8 @@
3
3
  module Usps
4
4
  module Imis
5
5
  module Panel
6
+ # Panel for accessing the annual VSC completed counts business object
7
+ #
6
8
  class Vsc < BasePanel
7
9
  private
8
10
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- VERSION = '1.0.0-rc.1'
5
+ VERSION = '1.0.0-rc.2'
6
6
  end
7
7
  end
data/lib/usps/imis.rb CHANGED
@@ -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
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.1
4
+ version: 1.0.0.pre.rc.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Fiander