halo_msp_api 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98f866a474dd58a86344301d4265af815a4d6582cabb6de0dfe5a94d572116d8
4
- data.tar.gz: 450ae6c2367fd9acb743fb6b81a183f6218de528868de4dafc63c8893f18cffb
3
+ metadata.gz: 66a71218fe73c35441a0f239ab1c80a3879aac9d9c44116c167a260c6cf6cb3c
4
+ data.tar.gz: 8602e863b06f0e4fd6ea315da702c6e9f1f8e41fdbdb3f19c22e08c4dd5ab91c
5
5
  SHA512:
6
- metadata.gz: b16bbea790fd1fbc1daf00ba83665261735569d9b0ab4d6fc0ce29562fdad32008220d950e59614712d74a43f476e452ab1e851c5336ea2639362096563c8d47
7
- data.tar.gz: 1b09d2963bed4af41b7c0e680cf814cb05981c8379b333ed67316a1bf589cd6f3da08f6ec134ded8dfa6c6a029dac038ce8e61764b5be28a3ab442f2783cd13d
6
+ metadata.gz: a4fbc442112b4f78af465735d8b59b74f3cfed6308306d42810a550729aafe6ed8a61815d904841a648e956a11c1aed92f15bfe512423a9c848895962d9d4be8
7
+ data.tar.gz: 300aebb149d31b354667abc6845598739e74f8b60008702f8c418b3ab0159646e53c40996e1e11c12591097bb5df9b5c33acf227ece2fa56a517978f95605ad7
data/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.0] - 2025-09-23
9
+
10
+ ### Added
11
+ - Added methods for grabbing ticket statuses, categories, and other user defined attributes
12
+
13
+ ### Fixed
14
+ - Fixed resource methods not using the correct method from the base class
15
+
16
+ ## [0.2.0] - 2025-09-15
17
+
18
+ ### Added
19
+ - Products Resource Class
20
+
21
+ ### Fixed
22
+ - Renamed Create/Update/Get/Delete methods in resource classes that caused an infinite recursion error
23
+ - Fixed specs that were failing due to naming mismatched/mocking API requests
24
+
25
+ ### Changed
26
+ - Updated `basic_usage.rb` examples to print specific data for verification
27
+ - Updated project to adhere to rubocop linting rules
28
+ - Removed support for Ruby 2.6 and 2.7 due to dependency incompatibilities
29
+
30
+ ### Deleted
31
+ - Removed `/me/` calls from Clients and Users since those calls returned 500 from the HaloPSA API
32
+
8
33
  ## [0.1.0] - 2025-07-10
9
34
 
10
35
  ### Added
data/Gemfile CHANGED
@@ -1,17 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in halo_api.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
8
+ gem 'rake', '~> 13.0'
9
9
 
10
10
  group :development, :test do
11
- gem "rspec", "~> 3.0"
12
- gem "rubocop", "~> 1.21"
13
- gem "yard", "~> 0.9"
14
- gem "webmock", "~> 3.0"
15
- gem "vcr", "~> 6.0"
16
- gem "pry", "~> 0.14"
11
+ gem 'pry'
17
12
  end
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # HaloMspApi Ruby Gem
2
2
 
3
+ [![Gem Version](https://img.shields.io/gem/v/halo_msp_api)](https://rubygems.org/gems/halo_msp_api)
4
+
3
5
  A comprehensive Ruby API wrapper for the Halo ITSM, HaloPSA and HaloCRM REST API.
4
6
 
5
7
  ## Installation
@@ -53,13 +55,13 @@ client = HaloApi::Client.new(config)
53
55
 
54
56
  ```ruby
55
57
  # List all tickets
56
- tickets = client.tickets.list
58
+ tickets = client.tickets.tickets
57
59
 
58
60
  # Get a specific ticket
59
- ticket = client.tickets.get(123)
61
+ ticket = client.tickets.ticket(123)
60
62
 
61
63
  # Create a new ticket
62
- new_ticket = client.tickets.create({
64
+ new_ticket = client.tickets.create_ticket({
63
65
  summary: "New ticket",
64
66
  details: "Ticket description",
65
67
  tickettype_id: 1,
@@ -67,23 +69,20 @@ new_ticket = client.tickets.create({
67
69
  })
68
70
 
69
71
  # Update a ticket
70
- client.tickets.update(123, { summary: "Updated summary" })
72
+ client.tickets.update_ticket(123, { summary: "Updated summary" })
71
73
 
72
74
  # Delete a ticket
73
- client.tickets.delete(123)
75
+ client.tickets.delete_ticket(123)
74
76
  ```
75
77
 
76
78
  ### Working with Users
77
79
 
78
80
  ```ruby
79
81
  # List all users
80
- users = client.users.list
81
-
82
- # Get current user
83
- current_user = client.users.me
82
+ users = client.users.users
84
83
 
85
84
  # Create a new user
86
- new_user = client.users.create({
85
+ new_user = client.users.create_user({
87
86
  name: "John Doe",
88
87
  emailaddress: "john@example.com"
89
88
  })
@@ -93,13 +92,13 @@ new_user = client.users.create({
93
92
 
94
93
  ```ruby
95
94
  # List all assets
96
- assets = client.assets.list
95
+ assets = client.assets.assets
97
96
 
98
97
  # Get a specific asset
99
- asset = client.assets.get(123)
98
+ asset = client.assets.asset(123)
100
99
 
101
100
  # Create a new asset
102
- new_asset = client.assets.create({
101
+ new_asset = client.assets.create_asset({
103
102
  inventory_number: "ASSET001",
104
103
  assettype_id: 1
105
104
  })
@@ -109,13 +108,13 @@ new_asset = client.assets.create({
109
108
 
110
109
  ```ruby
111
110
  # List all clients
112
- clients = client.clients.list
111
+ clients = client.clients.clients
113
112
 
114
113
  # Get a specific client
115
- client_record = client.clients.get(123)
114
+ client_record = client.clients.client(123)
116
115
 
117
116
  # Create a new client
118
- new_client = client.clients.create({
117
+ new_client = client.clients.create_client({
119
118
  name: "ACME Corp",
120
119
  website: "https://acme.com"
121
120
  })
@@ -125,13 +124,13 @@ new_client = client.clients.create({
125
124
 
126
125
  ```ruby
127
126
  # List all invoices
128
- invoices = client.invoices.list
127
+ invoices = client.invoices.invoices
129
128
 
130
129
  # Get a specific invoice
131
- invoice = client.invoices.get(123)
130
+ invoice = client.invoices.invoice(123)
132
131
 
133
132
  # Create a new invoice
134
- new_invoice = client.invoices.create({
133
+ new_invoice = client.invoices.create_invoice({
135
134
  client_id: 1,
136
135
  invoicedate: "2023-01-01"
137
136
  })
@@ -144,10 +143,10 @@ pdf_data = client.invoices.pdf(123)
144
143
 
145
144
  ```ruby
146
145
  # List all reports
147
- reports = client.reports.list
146
+ reports = client.reports.reports
148
147
 
149
148
  # Get a specific report
150
- report = client.reports.get(123)
149
+ report = client.reports.report(123)
151
150
 
152
151
  # Get report data
153
152
  report_data = client.reports.data("published_report_id")
@@ -157,10 +156,10 @@ report_data = client.reports.data("published_report_id")
157
156
 
158
157
  ```ruby
159
158
  # Get Azure AD data
160
- azure_data = client.integrations.get_azure_ad
159
+ azure_data = client.integrations.azure_ad
161
160
 
162
161
  # Get Slack data
163
- slack_data = client.integrations.get_slack
162
+ slack_data = client.integrations.slack
164
163
 
165
164
  # Import Jira data
166
165
  client.integrations.import_jira(jira_data)
@@ -185,6 +184,7 @@ The gem provides access to the following Halo API resources:
185
184
  - **Quotations** - `client.quotations` - Quote management, approvals
186
185
  - **Sales Orders** - `client.sales_orders` - Sales order management
187
186
  - **Suppliers** - `client.suppliers` - Supplier and contract management
187
+ - **Products** - `client.products` - Product management
188
188
 
189
189
  ### Service Management
190
190
  - **Appointments** - `client.appointments` - Scheduling and availability
@@ -207,20 +207,20 @@ The gem provides specific error classes for different types of API errors:
207
207
 
208
208
  ```ruby
209
209
  begin
210
- ticket = client.tickets.get(999999)
211
- rescue HaloApi::NotFoundError
210
+ ticket = client.tickets.ticket(999999)
211
+ rescue HaloMspApi::NotFoundError
212
212
  puts "Ticket not found"
213
- rescue HaloApi::AuthenticationError
213
+ rescue HaloMspApi::AuthenticationError
214
214
  puts "Authentication failed"
215
- rescue HaloApi::AuthorizationError
215
+ rescue HaloMspApi::AuthorizationError
216
216
  puts "Access forbidden"
217
- rescue HaloApi::ValidationError => e
217
+ rescue HaloMspApi::ValidationError => e
218
218
  puts "Validation error: #{e.message}"
219
- rescue HaloApi::RateLimitError
219
+ rescue HaloMspApi::RateLimitError
220
220
  puts "Rate limit exceeded"
221
- rescue HaloApi::ServerError
221
+ rescue HaloMspApi::ServerError
222
222
  puts "Server error"
223
- rescue HaloApi::APIError => e
223
+ rescue HaloMspApi::APIError => e
224
224
  puts "API error: #{e.message} (Status: #{e.status_code})"
225
225
  end
226
226
  ```
@@ -235,6 +235,6 @@ The gem is available as open source under the terms of the [MIT License](https:/
235
235
 
236
236
  ## Development
237
237
 
238
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
238
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rspec` to run the tests.
239
239
 
240
240
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require "rubocop/rake_task"
8
+ require 'rubocop/rake_task'
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
@@ -1,70 +1,134 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "bundler/setup"
5
- require "halo_msp_api"
4
+ require 'bundler/setup'
5
+ require 'halo_msp_api'
6
6
 
7
7
  # Configure the HaloMspApi gem
8
8
  HaloMspApi.configure do |config|
9
- config.base_url = ENV["HALO_BASE_URL"] || "https://your-instance.haloitsm.com/api"
10
- config.client_id = ENV["HALO_CLIENT_ID"] || "your_client_id"
11
- config.client_secret = ENV["HALO_CLIENT_SECRET"] || "your_client_secret"
12
- config.tenant = ENV["HALO_TENANT"] # Optional
9
+ config.base_url = ENV['HALO_BASE_URL'] || 'https://your-instance.haloitsm.com/api'
10
+ config.client_id = ENV['HALO_CLIENT_ID'] || 'your_client_id'
11
+ config.client_secret = ENV['HALO_CLIENT_SECRET'] || 'your_client_secret'
12
+ config.tenant = ENV['HALO_TENANT'] # Optional
13
13
  config.timeout = 30
14
14
  config.retries = 3
15
15
  end
16
16
 
17
17
  # Get a client instance
18
- client = HaloMspApi.client
18
+ instance = HaloMspApi.client
19
19
 
20
20
  begin
21
- puts "=== HaloApi Ruby Gem Example Usage ==="
21
+ puts '=== HaloApi Ruby Gem Example Usage ==='
22
22
  puts
23
23
 
24
24
  # Example 1: List tickets
25
- puts "1. Fetching tickets..."
26
- tickets = client.tickets.list(count: 5)
27
- puts "Found #{tickets.dig('tickets')&.length || 0} tickets"
25
+ puts '1. Fetching tickets...'
26
+ tickets = instance.tickets.tickets(count: 5)
27
+ puts "Found #{tickets['tickets']&.length || 0} tickets"
28
+ if tickets['tickets']&.any?
29
+ puts 'Ticket summaries:'
30
+ tickets['tickets'].each do |ticket|
31
+ puts "- #{ticket['summary'] || 'Unknown'}"
32
+ end
33
+ end
28
34
  puts
29
35
 
30
- # Example 2: Get current user
31
- puts "2. Fetching current user..."
32
- current_user = client.users.me
33
- puts "Current user: #{current_user.dig('name') || 'Unknown'}"
36
+ # Example 2: List users
37
+ puts '2. Fetching users...'
38
+ users = instance.users.users(count: 5)
39
+ puts "Found #{users['users']&.length || 0} users"
40
+ if users['users']&.any?
41
+ puts 'User names:'
42
+ users['users'].each do |user|
43
+ puts "- #{user['name'] || 'Unknown'}"
44
+ end
45
+ end
34
46
  puts
35
47
 
36
- # Example 3: List clients
37
- puts "3. Fetching clients..."
38
- clients = client.clients.list(count: 5)
39
- puts "Found #{clients.dig('clients')&.length || 0} clients"
48
+ # Example 3: List companies
49
+ puts '3. Fetching clients...'
50
+ clients = instance.clients.clients(count: 5)
51
+ puts "Found #{clients['clients']&.length || 0} clients"
52
+ if clients['clients']&.any?
53
+ puts 'Client names:'
54
+ clients['clients'].each do |client_item|
55
+ puts "- #{client_item['name'] || 'Unknown'}"
56
+ end
57
+ end
40
58
  puts
41
59
 
42
60
  # Example 4: List assets
43
- puts "4. Fetching assets..."
44
- assets = client.assets.list(count: 5)
45
- puts "Found #{assets.dig('assets')&.length || 0} assets"
61
+ puts '4. Fetching assets...'
62
+ assets = instance.assets.assets(count: 5)
63
+ puts "Found #{assets['assets']&.length || 0} assets"
64
+ if assets['assets']&.any?
65
+ puts 'Asset Inventory Number & Client Association:'
66
+ assets['assets'].each do |asset|
67
+ puts "- #{asset['inventory_number'] || 'Unknown'}: #{asset['client_name'] || 'Unknown'}"
68
+ end
69
+ end
46
70
  puts
47
71
 
48
72
  # Example 5: List invoices
49
- puts "5. Fetching invoices..."
50
- invoices = client.invoices.list(count: 5)
51
- puts "Found #{invoices.dig('invoices')&.length || 0} invoices"
73
+ puts '5. Fetching invoices...'
74
+ invoices = instance.invoices.invoices(count: 5)
75
+ puts "Found #{invoices['invoices']&.length || 0} invoices"
76
+ if invoices['invoices']&.any?
77
+ puts 'Invoice ID and Client Association:'
78
+ invoices['invoices'].each do |invoice|
79
+ puts "- #{invoice['id'] || 'Unknown'}: #{invoice['client_name'] || 'Unknown'}"
80
+ end
81
+ end
52
82
  puts
53
83
 
54
84
  # Example 6: Get reports
55
- puts "6. Fetching reports..."
56
- reports = client.reports.list(count: 5)
57
- puts "Found #{reports.dig('reports')&.length || 0} reports"
85
+ puts '6. Fetching reports...'
86
+ reports = instance.reports.reports(count: 5)
87
+ puts "Found #{reports['reports']&.length || 0} reports"
88
+ if reports['reports']&.any?
89
+ puts 'Report Names:'
90
+ reports['reports'].each do |report|
91
+ puts "- #{report['name'] || 'Unknown'}"
92
+ end
93
+ end
58
94
  puts
59
95
 
60
- puts "=== Example completed successfully! ==="
96
+ # Example 7: Get contracts
97
+ puts '7. Fetching contracts...'
98
+ contracts = instance.clients.contracts(count: 5)
99
+ puts "Found #{contracts['contracts']&.length || 0} contracts"
100
+ if contracts['contracts']&.any?
101
+ puts 'Contract Client & Active:'
102
+ contracts['contracts'].each do |contract|
103
+ puts "- #{contract['client_name'] || 'Unknown'}: #{contract['active'] || 'Unknown'}"
104
+ end
105
+ end
106
+ puts
107
+
108
+ # Example 8: Get products
109
+ puts '8. Fetching products...'
110
+ products = instance.products.products(count: 5)
111
+ puts "Found #{products['items']&.length || 0} products"
112
+ if products['items']&.any?
113
+ puts 'Product Names:'
114
+ products['items'].each do |product|
115
+ puts "- #{product['name'] || 'Unknown'}"
116
+ end
117
+ end
118
+ puts
119
+
120
+ puts '9. Listing Statuses'
121
+ statuses = instance.tickets.statuses
122
+ puts "Found #{statuses&.length || 0} statuses"
123
+ puts "First Status: #{statuses.first['name']}"
61
124
 
125
+ puts '=== Example completed successfully! ==='
62
126
  rescue HaloMspApi::AuthenticationError => e
63
127
  puts "Authentication failed: #{e.message}"
64
- puts "Please check your client_id and client_secret"
128
+ puts 'Please check your client_id and client_secret'
65
129
  rescue HaloMspApi::AuthorizationError => e
66
130
  puts "Authorization failed: #{e.message}"
67
- puts "Please check your permissions"
131
+ puts 'Please check your permissions'
68
132
  rescue HaloMspApi::APIError => e
69
133
  puts "API Error: #{e.message}"
70
134
  puts "Status Code: #{e.status_code}" if e.respond_to?(:status_code)
@@ -1,16 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "faraday"
4
- require "faraday/retry"
5
- require "json"
3
+ require 'faraday'
4
+ require 'faraday/retry'
5
+ require 'json'
6
6
 
7
7
  module HaloMspApi
8
+ # Client class for Halo MSP API
9
+ # rubocop:disable Metrics/ClassLength
8
10
  class Client
9
11
  attr_reader :configuration, :connection
10
12
 
11
13
  def initialize(configuration = nil)
12
- @configuration = configuration || HaloApi.configuration
13
- raise ConfigurationError, "Configuration is required" unless @configuration&.valid?
14
+ @configuration = configuration || HaloMspApi.configuration
15
+ raise ConfigurationError, 'Configuration is required' unless @configuration&.valid?
14
16
 
15
17
  @connection = build_connection
16
18
  @access_token = nil
@@ -38,6 +40,10 @@ module HaloMspApi
38
40
  @clients ||= Resources::Clients.new(self)
39
41
  end
40
42
 
43
+ def contracts
44
+ @contracts ||= Resources::Contracts.new(self)
45
+ end
46
+
41
47
  def integrations
42
48
  @integrations ||= Resources::Integrations.new(self)
43
49
  end
@@ -54,6 +60,10 @@ module HaloMspApi
54
60
  @organisations ||= Resources::Organisations.new(self)
55
61
  end
56
62
 
63
+ def products
64
+ @products ||= Resources::Products.new(self)
65
+ end
66
+
57
67
  def purchase_orders
58
68
  @purchase_orders ||= Resources::PurchaseOrders.new(self)
59
69
  end
@@ -117,13 +127,15 @@ module HaloMspApi
117
127
 
118
128
  private
119
129
 
130
+ # rubocop:disable Metrics/AbcSize
131
+ # rubocop:disable Metrics/MethodLength
120
132
  def request(method, path, data = {})
121
133
  ensure_authenticated!
122
134
 
123
135
  response = connection.send(method) do |req|
124
136
  req.url path
125
- req.headers["Authorization"] = "Bearer #{@access_token}"
126
- req.headers["Content-Type"] = "application/json"
137
+ req.headers['Authorization'] = "Bearer #{@access_token}"
138
+ req.headers['Content-Type'] = 'application/json'
127
139
 
128
140
  if %i[post put patch].include?(method) && !data.empty?
129
141
  req.body = data.to_json
@@ -134,31 +146,37 @@ module HaloMspApi
134
146
 
135
147
  handle_response(response)
136
148
  rescue Faraday::TimeoutError
137
- raise TimeoutError, "Request timed out"
149
+ raise TimeoutError, 'Request timed out'
138
150
  rescue Faraday::ConnectionFailed
139
- raise ConnectionError, "Connection failed"
151
+ raise ConnectionError, 'Connection failed'
140
152
  end
153
+ # rubocop:enable Metrics/AbcSize
154
+ # rubocop:enable Metrics/MethodLength
141
155
 
156
+ # rubocop:disable Metrics/CyclomaticComplexity
157
+ # rubocop:disable Metrics/MethodLength
142
158
  def handle_response(response)
143
159
  case response.status
144
160
  when 200..299
145
161
  parse_response(response)
146
162
  when 401
147
- raise AuthenticationError, "Authentication failed"
163
+ raise AuthenticationError, 'Authentication failed'
148
164
  when 403
149
- raise AuthorizationError, "Access forbidden"
165
+ raise AuthorizationError, 'Access forbidden'
150
166
  when 404
151
- raise NotFoundError, "Resource not found"
167
+ raise NotFoundError, 'Resource not found'
152
168
  when 422
153
169
  raise ValidationError, "Validation error: #{response.body}"
154
170
  when 429
155
- raise RateLimitError, "Rate limit exceeded"
171
+ raise RateLimitError, 'Rate limit exceeded'
156
172
  when 500..599
157
173
  raise ServerError, "Server error: #{response.status}"
158
174
  else
159
- raise APIError.new("Unexpected response", status_code: response.status, response_body: response.body)
175
+ raise APIError.new('Unexpected response', status_code: response.status, response_body: response.body)
160
176
  end
161
177
  end
178
+ # rubocop:enable Metrics/CyclomaticComplexity
179
+ # rubocop:enable Metrics/MethodLength
162
180
 
163
181
  def parse_response(response)
164
182
  return nil if response.body.nil? || response.body.empty?
@@ -178,32 +196,34 @@ module HaloMspApi
178
196
  @access_token && @token_expires_at && Time.now < @token_expires_at
179
197
  end
180
198
 
199
+ # rubocop:disable Metrics/AbcSize
200
+ # rubocop:disable Metrics/MethodLength
181
201
  def authenticate!
182
202
  auth_params = {
183
- grant_type: "client_credentials",
203
+ grant_type: 'client_credentials',
184
204
  client_id: configuration.client_id,
185
205
  client_secret: configuration.client_secret,
186
- scope: "all"
206
+ scope: 'all'
187
207
  }
188
-
208
+
189
209
  # Include tenant if configured (required for multi-tenant instances)
190
210
  auth_params[:tenant] = configuration.tenant if configuration.tenant
191
-
192
- auth_response = connection.post("/auth/token") do |req|
193
- req.headers["Content-Type"] = "application/x-www-form-urlencoded"
211
+
212
+ auth_response = connection.post('/auth/token') do |req|
213
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
194
214
  req.body = URI.encode_www_form(auth_params)
195
215
  end
196
216
 
197
- if auth_response.status == 200
198
- token_data = JSON.parse(auth_response.body)
199
- @access_token = token_data["access_token"]
200
- @token_expires_at = Time.now + token_data["expires_in"].to_i
201
- else
202
- raise AuthenticationError, "Failed to authenticate: #{auth_response.body}"
203
- end
217
+ raise AuthenticationError, "Failed to authenticate: #{auth_response.body}" unless auth_response.status == 200
218
+
219
+ token_data = JSON.parse(auth_response.body)
220
+ @access_token = token_data['access_token']
221
+ @token_expires_at = Time.now + token_data['expires_in'].to_i
204
222
  rescue JSON::ParserError
205
- raise AuthenticationError, "Invalid authentication response"
223
+ raise AuthenticationError, 'Invalid authentication response'
206
224
  end
225
+ # rubocop:enable Metrics/AbcSize
226
+ # rubocop:enable Metrics/MethodLength
207
227
 
208
228
  def build_connection
209
229
  Faraday.new(url: configuration.base_url) do |conn|
@@ -214,3 +234,4 @@ module HaloMspApi
214
234
  end
215
235
  end
216
236
  end
237
+ # rubocop:enable Metrics/ClassLength
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HaloMspApi
4
+ # HaloMspApi Configuration Class
4
5
  class Configuration
5
6
  attr_accessor :base_url, :client_id, :client_secret, :tenant, :timeout, :retries
6
7
 
@@ -13,6 +13,7 @@ module HaloMspApi
13
13
  class TimeoutError < Error; end
14
14
  class ConnectionError < Error; end
15
15
 
16
+ # Class for handling API Errors
16
17
  class APIError < Error
17
18
  attr_reader :status_code, :response_body
18
19