ninjaone 0.1.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 +7 -0
- data/.env.template +2 -0
- data/.gitignore +44 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +11 -0
- data/README.md +132 -0
- data/Rakefile +18 -0
- data/lib/ninjaone/api.rb +57 -0
- data/lib/ninjaone/authentication.rb +75 -0
- data/lib/ninjaone/client/organizations.rb +48 -0
- data/lib/ninjaone/client/system.rb +39 -0
- data/lib/ninjaone/client.rb +59 -0
- data/lib/ninjaone/error.rb +30 -0
- data/lib/ninjaone/version.rb +5 -0
- data/lib/ninjaone.rb +50 -0
- data/ninjaone.gemspec +37 -0
- metadata +139 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b308dc5c61be46c792940ed58dc52596fa4146a1573e49db047396b1f959df61
|
|
4
|
+
data.tar.gz: 5cf673637b6af95d97ce82d81fd42970e47608aba6f018412b1d9c219f069c6a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 07a6c00f22eaaebcf0053a140641f642c93d89cdf898626c08dd72f364a87e55a16266d690571be0a4252e3502265d94619a79c34f7da692b584cce6edb7e410
|
|
7
|
+
data.tar.gz: d0a45f7032e93a8581e8a49976fdc7e7e2928cf18f657dd707fedadef5352e0ca84dd48b21ed25d434d9737c3c7597d4acca35bcfb775ffd5782759b0b916b3a
|
data/.env.template
ADDED
data/.gitignore
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/tmp/
|
|
10
|
+
/test/version_tmp/
|
|
11
|
+
/tmp/
|
|
12
|
+
/data/
|
|
13
|
+
*.log
|
|
14
|
+
*.txt
|
|
15
|
+
*.json
|
|
16
|
+
*.yml
|
|
17
|
+
|
|
18
|
+
# Used by dotenv library to load environment variables.
|
|
19
|
+
.env
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Documentation cache and generated files:
|
|
23
|
+
/.yardoc/
|
|
24
|
+
/_yardoc/
|
|
25
|
+
/doc/
|
|
26
|
+
/rdoc/
|
|
27
|
+
|
|
28
|
+
## Environment normalization:
|
|
29
|
+
/.bundle/
|
|
30
|
+
/vendor/bundle
|
|
31
|
+
/lib/bundler/man/
|
|
32
|
+
|
|
33
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
34
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
35
|
+
# Gemfile.lock
|
|
36
|
+
# .ruby-version
|
|
37
|
+
# .ruby-gemset
|
|
38
|
+
|
|
39
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
40
|
+
.rvmrc
|
|
41
|
+
|
|
42
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
|
43
|
+
# .rubocop-https?--*
|
|
44
|
+
Gemfile.lock
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# NinjaOne RMM API
|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/ninjaone)
|
|
4
|
+
|
|
5
|
+
This is a wrapper for the ninjaone API.
|
|
6
|
+
You can see the [API endpoints](https://app.ninjarmm.com/apidocs/)
|
|
7
|
+
|
|
8
|
+
Currently only the GET requests to endpoints
|
|
9
|
+
are implemented (readonly).
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Add this line to your application's Gemfile:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
gem 'ninjaone'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
And then execute:
|
|
20
|
+
|
|
21
|
+
```console
|
|
22
|
+
> bundle install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or install it yourself as:
|
|
26
|
+
|
|
27
|
+
```console
|
|
28
|
+
> gem install ninjaone
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Authentication
|
|
34
|
+
|
|
35
|
+
Before you start making the requests to API provide the client id and client secret
|
|
36
|
+
and email/password using the configuration wrapping.
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
require 'ninjaone'
|
|
40
|
+
|
|
41
|
+
NinjaOne.configure do |config|
|
|
42
|
+
config.client_id = ENV['NINJA1_CLIENT_ID']
|
|
43
|
+
config.client_secret = ENV['NINJA1_CLIENT_SECRET']
|
|
44
|
+
config.endpoint = ENV['NINJA1_ENDPOINT']
|
|
45
|
+
end
|
|
46
|
+
client = NinjaOne.client()
|
|
47
|
+
client.login
|
|
48
|
+
|
|
49
|
+
o = client.organizations
|
|
50
|
+
|
|
51
|
+
o.each do |organization|
|
|
52
|
+
puts "#{organization.name}"
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Resources
|
|
57
|
+
|
|
58
|
+
### Authentication
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
# setup configuration
|
|
62
|
+
#
|
|
63
|
+
client.login
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
|Resource|API endpoint|
|
|
68
|
+
|:--|:--|
|
|
69
|
+
|.auth_token or .login|https://app.ninjarmm.com/apidocs/?links.active=authorization|
|
|
70
|
+
|
|
71
|
+
### System
|
|
72
|
+
|
|
73
|
+
Core system Entities and Resources
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
subscriptions = client.subscriptions
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
|Resource|API endpoint|
|
|
80
|
+
|:--|:--|
|
|
81
|
+
|contacts, contact(id)|List contact and get contact details|
|
|
82
|
+
|organizations|list organizations|
|
|
83
|
+
|policies|list policies|
|
|
84
|
+
|jobs|list active jobs|
|
|
85
|
+
|activities|list activities|
|
|
86
|
+
|alerts|List active alerts (triggered conditions)|
|
|
87
|
+
|automation_scripts|List available automation scripts|
|
|
88
|
+
|device_custom_fields|List device custom fields|
|
|
89
|
+
|devices|List devices|
|
|
90
|
+
|devices_detailed|List devices(deatiled)|
|
|
91
|
+
|enabled_notification_channels|List enabled notification channels|
|
|
92
|
+
|notification_channels|List all notification channels|
|
|
93
|
+
|notification_channels_detailed|List all notification channels detailed|
|
|
94
|
+
|groups|List all groups (saved searches)|
|
|
95
|
+
|locations|List all locations|
|
|
96
|
+
|roles|List device roles|
|
|
97
|
+
|tasks|List scheduled tasks|
|
|
98
|
+
|software_products|List supported 3rd party software|
|
|
99
|
+
|users|List users|
|
|
100
|
+
|search_devices(query_string)|Find devices|
|
|
101
|
+
|user_end_users|End user list|
|
|
102
|
+
|user_technicians|Technicians list|
|
|
103
|
+
|user_roles|Get user roles|
|
|
104
|
+
|
|
105
|
+
### Organizations
|
|
106
|
+
|
|
107
|
+
All apis related to organizations
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
org = client.organizations.first
|
|
111
|
+
org_devices = client.organization_devices(org.id)
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
|Resource|API endpoint|
|
|
116
|
+
|:--|:--|
|
|
117
|
+
|.organizations,.organization(id)|List organizations or get one by id|
|
|
118
|
+
|.organization_locations(id)|Organization locations|
|
|
119
|
+
|.organization_end_users(id)|List users|
|
|
120
|
+
|.organization_custom_fields(id)|Organization custom fields|
|
|
121
|
+
|.organization_devices(id)|Organization devices|
|
|
122
|
+
|.organization_locations_backup_usage(id)|Organization location backup usage|
|
|
123
|
+
|.organization_backup_usage_by_location(id, location_id)|Organization locations backup usage|
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
## Contributing
|
|
127
|
+
|
|
128
|
+
Bug reports and pull requests are welcome on [GitHub](https://github.com/jancotanis/ninjaone).
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
4
|
+
require 'dotenv'
|
|
5
|
+
require 'rake/testtask'
|
|
6
|
+
|
|
7
|
+
Dotenv.load
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
Rake::TestTask.new(:test) do |t|
|
|
11
|
+
t.libs << 'test'
|
|
12
|
+
t.libs << 'lib'
|
|
13
|
+
t.test_files = FileList['test/**/*_test.rb']
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
require 'rubocop/rake_task'
|
|
17
|
+
RuboCop::RakeTask.new
|
|
18
|
+
task default: %i[test rubocop]
|
data/lib/ninjaone/api.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'wrapi'
|
|
4
|
+
#require File.expand_path('connection', __dir__)
|
|
5
|
+
require File.expand_path('authentication', __dir__)
|
|
6
|
+
|
|
7
|
+
module NinjaOne
|
|
8
|
+
# The `NinjaOne::API` class manages the core configuration and settings for the API client.
|
|
9
|
+
# It allows customization of options like endpoint, user agent, and pagination handling.
|
|
10
|
+
# This class copies configuration settings from the NinjaOne singleton and provides methods to retrieve the client configuration.
|
|
11
|
+
class API
|
|
12
|
+
# Dynamically create accessor methods for all valid configuration keys.
|
|
13
|
+
attr_accessor(*WrAPI::Configuration::VALID_OPTIONS_KEYS)
|
|
14
|
+
|
|
15
|
+
# Initializes a new `NinjaOne::API` instance with the given options.
|
|
16
|
+
# The options are merged with the global NinjaOne settings to allow both global and per-instance customization.
|
|
17
|
+
#
|
|
18
|
+
# @param options [Hash] A hash of configuration options.
|
|
19
|
+
# These options can override the global NinjaOne configuration.
|
|
20
|
+
#
|
|
21
|
+
# @example Create a new API instance with custom options:
|
|
22
|
+
# api = NinjaOne::API.new(endpoint: "https://custom-api.endpoint.com", user_agent: "MyApp UA/1.0")
|
|
23
|
+
#
|
|
24
|
+
# @return [NinjaOne::API] A new instance of the NinjaOne API with the specified options.
|
|
25
|
+
def initialize(options = {})
|
|
26
|
+
# Merge the provided options with the global NinjaOne configuration.
|
|
27
|
+
options = NinjaOne.options.merge(options)
|
|
28
|
+
# Set each configuration key dynamically using the merged options.
|
|
29
|
+
WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
|
30
|
+
send("#{key}=", options[key])
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Retrieves the current API configuration as a hash.
|
|
35
|
+
#
|
|
36
|
+
# @return [Hash] A hash containing the current configuration settings.
|
|
37
|
+
# The keys in the hash are the same as `VALID_OPTIONS_KEYS`.
|
|
38
|
+
#
|
|
39
|
+
# @example Retrieve the current API configuration:
|
|
40
|
+
# api = NinjaOne::API.new
|
|
41
|
+
# api.config # => { :endpoint => "https://apis.skykick.com", :user_agent => "NinjaOne API/1.0", ... }
|
|
42
|
+
def config
|
|
43
|
+
conf = {}
|
|
44
|
+
# Iterate over each valid configuration key and retrieve its current value.
|
|
45
|
+
WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
|
46
|
+
conf[key] = send key
|
|
47
|
+
end
|
|
48
|
+
conf
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Include core modules for API functionality, including HTTP connections, request handling, and authentication.
|
|
52
|
+
include WrAPI::Connection
|
|
53
|
+
include WrAPI::Request
|
|
54
|
+
include WrAPI::Authentication
|
|
55
|
+
include Authentication
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require File.expand_path('error', __dir__)
|
|
4
|
+
require 'uri'
|
|
5
|
+
|
|
6
|
+
module NinjaOne
|
|
7
|
+
# The `NinjaOne::Authentication` module handles the authentication flow for the NinjaOne API.
|
|
8
|
+
# It manages access tokens and stores them in the global configuration.
|
|
9
|
+
# This module provides methods to log in to the NinjaOne portal using client credentials.
|
|
10
|
+
#
|
|
11
|
+
# @see https://developers.skykick.com/Guides/Authentication
|
|
12
|
+
module Authentication
|
|
13
|
+
# Authenticates with the NinjaOne API and retrieves an access token.
|
|
14
|
+
#
|
|
15
|
+
# This method performs a client credentials flow to authenticate with the NinjaOne API.
|
|
16
|
+
# The access token is stored in the global configuration for subsequent API calls.
|
|
17
|
+
#
|
|
18
|
+
# @param _options [Hash] Options for the authentication request (currently unused).
|
|
19
|
+
# @return [String] The access token for authenticated API requests.
|
|
20
|
+
#
|
|
21
|
+
# @raise [ConfigurationError] If `client_id`, `client_secret` or `endpoint` are not configured.
|
|
22
|
+
# @raise [AuthenticationError] If the authentication fails due to invalid credentials or other issues.
|
|
23
|
+
#
|
|
24
|
+
# @example Authenticate and retrieve an access token:
|
|
25
|
+
# token = NinjaOne::Authentication.auth_token
|
|
26
|
+
def auth_token(_options = {})
|
|
27
|
+
raise ConfigurationError.new 'Client id and/or secret not configured' unless client_id && client_secret
|
|
28
|
+
raise ConfigurationError.new 'Endpoint not configured' unless endpoint
|
|
29
|
+
|
|
30
|
+
con = connection
|
|
31
|
+
response = con.post('/ws/oauth/token') do |request|
|
|
32
|
+
request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
33
|
+
request.body = URI.encode_www_form(api_access_token_params)
|
|
34
|
+
end
|
|
35
|
+
api_process_token(response.body)
|
|
36
|
+
|
|
37
|
+
self.access_token
|
|
38
|
+
rescue Faraday::ForbiddenError, Faraday::BadRequestError, Faraday::ResourceNotFound => e
|
|
39
|
+
raise AuthenticationError.new "Unauthorized; response #{e}"
|
|
40
|
+
end
|
|
41
|
+
alias login auth_token
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# Prepares the parameters required for the authentication request.
|
|
46
|
+
#
|
|
47
|
+
# @return [Hash] The parameters for the API access token request.
|
|
48
|
+
def api_access_token_params
|
|
49
|
+
{
|
|
50
|
+
grant_type: 'client_credentials',
|
|
51
|
+
client_id: client_id,
|
|
52
|
+
client_secret: client_secret,
|
|
53
|
+
scope: 'monitoring management control'
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Processes the response from the NinjaOne API and extracts authentication details.
|
|
58
|
+
#
|
|
59
|
+
# @param response [Hash] The parsed response body from the API.
|
|
60
|
+
#
|
|
61
|
+
# @return [void]
|
|
62
|
+
#
|
|
63
|
+
# @raise [AuthorizationError] If the response does not include a valid `access_token`.
|
|
64
|
+
def api_process_token(response)
|
|
65
|
+
self.access_token = response['access_token']
|
|
66
|
+
self.token_type = response['token_type']
|
|
67
|
+
self.refresh_token = response['refresh_token']
|
|
68
|
+
self.token_expires = response['expires_in']
|
|
69
|
+
|
|
70
|
+
if self.access_token.nil? || self.access_token.empty?
|
|
71
|
+
raise AuthorizationError.new "Could not find valid access_token; response #{response}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NinjaOne
|
|
4
|
+
class Client
|
|
5
|
+
# Contains Organizations API calls for Ninja One.
|
|
6
|
+
#
|
|
7
|
+
# @see https://app.ninjarmm.com/apidocs/?links.active=core#/organization Ninja One Developer Documentation
|
|
8
|
+
module Organizations
|
|
9
|
+
# Dynamically defines methods for interacting with NinjaOne API resources.
|
|
10
|
+
#
|
|
11
|
+
# Depending on the arguments, this will define methods to:
|
|
12
|
+
# - Fetch all records for a resource
|
|
13
|
+
# - Fetch a specific record by ID
|
|
14
|
+
#
|
|
15
|
+
# @param method [Symbol] The method name for fetching all records.
|
|
16
|
+
# @param singular_method [Symbol, nil] The method name for fetching a single record by ID. Optional.
|
|
17
|
+
# @param path [String] The API path for the resource. Defaults to the method name.
|
|
18
|
+
#
|
|
19
|
+
# @example Defining endpoints
|
|
20
|
+
# api_endpoint :companies, :company
|
|
21
|
+
# # Defines:
|
|
22
|
+
# # - `companies(params = {})` to fetch all companies.
|
|
23
|
+
# # - `company(id, params = {})` to fetch a single company by ID.
|
|
24
|
+
def self.api_endpoint_suffix(method, suffix)
|
|
25
|
+
# Define method to fetch a single record by ID
|
|
26
|
+
name = "#{method}_#{suffix.gsub(/[-\/]/,'_')}"
|
|
27
|
+
|
|
28
|
+
send(:define_method, name) do |id, params = {}|
|
|
29
|
+
get(api_url("#{method}/#{id}/#{suffix}"), params)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
api_endpoint_suffix(:organization, 'locations')
|
|
34
|
+
api_endpoint_suffix(:organization, 'end-users')
|
|
35
|
+
api_endpoint_suffix(:organization, 'custom-fields')
|
|
36
|
+
api_endpoint_suffix(:organization, 'devices')
|
|
37
|
+
api_endpoint_suffix(:organization, 'locations/backup/usage')
|
|
38
|
+
|
|
39
|
+
# Returns a location backup usage
|
|
40
|
+
def organization_backup_usage_by_location(id, location_id, params={})
|
|
41
|
+
get(api_url("organization/#{id}/locations/#{location_id}/backup/usage"), params)
|
|
42
|
+
rescue Faraday::ServerError
|
|
43
|
+
# it looks like a server error is thrown when no backup is available; fake it by returning anempty array
|
|
44
|
+
[]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NinjaOne
|
|
4
|
+
class Client
|
|
5
|
+
# Contains Core system Entities and Resources API calls for Ninja One.
|
|
6
|
+
#
|
|
7
|
+
# @see https://app.ninjarmm.com/apidocs/?links.active=core#/system Ninja One Developer Documentation
|
|
8
|
+
module System
|
|
9
|
+
|
|
10
|
+
Client::api_endpoint(:contacts, :contact)
|
|
11
|
+
Client::api_endpoint(:organizations,:organization)
|
|
12
|
+
Client::api_endpoint(:organizations_detailed)
|
|
13
|
+
Client::api_endpoint(:policies)
|
|
14
|
+
Client::api_endpoint(:jobs)
|
|
15
|
+
Client::api_endpoint(:activities)
|
|
16
|
+
Client::api_endpoint(:alerts)
|
|
17
|
+
Client::api_endpoint(:automation_scripts, nil, 'automation/scripts')
|
|
18
|
+
Client::api_endpoint(:devices)
|
|
19
|
+
Client::api_endpoint(:devices_detailed)
|
|
20
|
+
Client::api_endpoint(:enabled_notification_channels, nil, 'notification-channels/enabled')
|
|
21
|
+
Client::api_endpoint(:notification_channels)
|
|
22
|
+
Client::api_endpoint(:groups)
|
|
23
|
+
Client::api_endpoint(:locations)
|
|
24
|
+
Client::api_endpoint(:roles)
|
|
25
|
+
Client::api_endpoint(:tasks)
|
|
26
|
+
Client::api_endpoint(:software_products)
|
|
27
|
+
Client::api_endpoint(:users)
|
|
28
|
+
Client::api_endpoint(:user_end_users, nil, 'user/end-users')
|
|
29
|
+
Client::api_endpoint(:user_roles, nil, 'user/roles')
|
|
30
|
+
Client::api_endpoint(:user_technicians, nil, 'user/technicians')
|
|
31
|
+
Client::api_endpoint(:devices_search, nil, 'devices/search')
|
|
32
|
+
|
|
33
|
+
def search_devices(query_string, options={})
|
|
34
|
+
devices_search(options.merge({q:query_string}))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NinjaOne
|
|
4
|
+
|
|
5
|
+
# The `NinjaOne::Client` class acts as a wrapper for the NinjaOne REST API.
|
|
6
|
+
# This class inherits from the `NinjaOne::API` class and includes modules that group
|
|
7
|
+
# the API methods according to the structure in the NinjaOne API documentation.
|
|
8
|
+
#
|
|
9
|
+
# @note All methods are grouped in separate modules for better organization and follow the structure provided in the official API documentation.
|
|
10
|
+
# @see https://developers.skykick.com/Guides/Authentication
|
|
11
|
+
class Client < API
|
|
12
|
+
# Dynamically defines methods for interacting with NinjaOne API resources.
|
|
13
|
+
#
|
|
14
|
+
# Depending on the arguments, this will define methods to:
|
|
15
|
+
# - Fetch all records for a resource
|
|
16
|
+
# - Fetch a specific record by ID
|
|
17
|
+
#
|
|
18
|
+
# @param method [Symbol] The method name for fetching all records.
|
|
19
|
+
# @param singular_method [Symbol, nil] The method name for fetching a single record by ID. Optional.
|
|
20
|
+
# @param path [String] The API path for the resource. Defaults to the method name.
|
|
21
|
+
#
|
|
22
|
+
# @example Defining endpoints
|
|
23
|
+
# api_endpoint :companies, :company
|
|
24
|
+
# # Defines:
|
|
25
|
+
# # - `companies(params = {})` to fetch all companies.
|
|
26
|
+
# # - `company(id, params = {})` to fetch a single company by ID.
|
|
27
|
+
def self.api_endpoint(method, singular_method = nil, path = method.to_s.tr('_', '-'))
|
|
28
|
+
# Define method to fetch all records
|
|
29
|
+
send(:define_method, method) do |params = {}|
|
|
30
|
+
get_paged(api_url(path), params)
|
|
31
|
+
end
|
|
32
|
+
# Define method to fetch a single record by ID
|
|
33
|
+
if singular_method
|
|
34
|
+
send(:define_method, singular_method) do |id, params = {}|
|
|
35
|
+
get(api_url("#{singular_method}/#{id}"), params)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Dynamically require all files in the `client` directory.
|
|
41
|
+
# This will load additional API modules as separate files for better modularity and code organization.
|
|
42
|
+
Dir[File.expand_path('client/*.rb', __dir__)].each { |f| require f }
|
|
43
|
+
|
|
44
|
+
# Include API client modules for specific NinjaOne API functionalities.
|
|
45
|
+
# These modules provide methods for interacting with specific parts of the NinjaOne API,
|
|
46
|
+
# such as managing backups and handling alerts.
|
|
47
|
+
include NinjaOne::Client::System
|
|
48
|
+
include NinjaOne::Client::Organizations
|
|
49
|
+
|
|
50
|
+
# Constructs the full API URL for a given path.
|
|
51
|
+
#
|
|
52
|
+
# @param path [String] The API path.
|
|
53
|
+
# @return [String] The full API URL.
|
|
54
|
+
def api_url(path)
|
|
55
|
+
"/v2/#{path}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NinjaOne
|
|
4
|
+
# Base error class for all exceptions raised by the NinjaOne API.
|
|
5
|
+
# This allows rescuing all NinjaOne-related errors in a single block if desired.
|
|
6
|
+
# Example:
|
|
7
|
+
# begin
|
|
8
|
+
# # Code that interacts with the NinjaOne API
|
|
9
|
+
# rescue NinjaOne::NinjaOneError => e
|
|
10
|
+
# puts "An error occurred: #{e.message}"
|
|
11
|
+
# end
|
|
12
|
+
class NinjaOneError < StandardError; end
|
|
13
|
+
|
|
14
|
+
# Raised when the NinjaOne API configuration is incomplete or incorrect.
|
|
15
|
+
# This might occur if required configuration options such as `client_id`, `client_secret`,
|
|
16
|
+
# or `endpoint` are missing or improperly set.
|
|
17
|
+
#
|
|
18
|
+
# Example:
|
|
19
|
+
# raise NinjaOne::ConfigurationError, "Endpoint, Client ID and Secret must be configured"
|
|
20
|
+
class ConfigurationError < NinjaOneError; end
|
|
21
|
+
|
|
22
|
+
# Raised when authentication to the NinjaOne API fails.
|
|
23
|
+
# This might be due to incorrect credentials, an expired token, or insufficient permissions.
|
|
24
|
+
#
|
|
25
|
+
# Example:
|
|
26
|
+
# raise NinjaOne::AuthenticationError, "Invalid client credentials"
|
|
27
|
+
#
|
|
28
|
+
# @see https://developers.skykick.com/Guides/Authentication
|
|
29
|
+
class AuthenticationError < NinjaOneError; end
|
|
30
|
+
end
|
data/lib/ninjaone.rb
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'wrapi'
|
|
4
|
+
require File.expand_path('ninjaone/api', __dir__)
|
|
5
|
+
require File.expand_path('ninjaone/client', __dir__)
|
|
6
|
+
require File.expand_path('ninjaone/version', __dir__)
|
|
7
|
+
|
|
8
|
+
# The `NinjaOne` module is a wrapper around NinjaOne's API.
|
|
9
|
+
# It provides a client configuration, including default settings like endpoint URL and user agent.
|
|
10
|
+
# This module extends `WrAPI::Configuration` to provide configuration
|
|
11
|
+
# options and `WrAPI::RespondTo` for dynamic response handling.
|
|
12
|
+
module NinjaOne
|
|
13
|
+
extend WrAPI::Configuration
|
|
14
|
+
extend WrAPI::RespondTo
|
|
15
|
+
|
|
16
|
+
# Default User-Agent header sent with API requests, including gem version information.
|
|
17
|
+
DEFAULT_UA = "NinjaOne Ruby API wrapper #{NinjaOne::VERSION}"
|
|
18
|
+
|
|
19
|
+
# Creates and returns a new NinjaOne API client with the given options.
|
|
20
|
+
#
|
|
21
|
+
# @param options [Hash] A hash of configuration options to initialize the client.
|
|
22
|
+
# This method merges the provided options with default values such as endpoint, user agent, and pagination class.
|
|
23
|
+
#
|
|
24
|
+
# @option options [String] :endpoint The base URL for the NinjaOne API (default: `DEFAULT_ENDPOINT`).
|
|
25
|
+
# @option options [String] :user_agent The User-Agent header to send with each API request (default: `DEFAULT_UA`).
|
|
26
|
+
#
|
|
27
|
+
# @return [NinjaOne::Client] A new instance of the NinjaOne API client.
|
|
28
|
+
#
|
|
29
|
+
# @example Create a NinjaOne client:
|
|
30
|
+
# client = NinjaOne.client(endpoint: "https://api.custom-endpoint.com", user_agent: "Custom UA/1.0")
|
|
31
|
+
def self.client(options = {})
|
|
32
|
+
NinjaOne::Client.new({
|
|
33
|
+
user_agent: DEFAULT_UA
|
|
34
|
+
}.merge(options))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Resets the NinjaOne configuration to default values.
|
|
38
|
+
#
|
|
39
|
+
# This method resets the configuration values to their defaults:
|
|
40
|
+
# - `DEFAULT_ENDPOINT` for the API endpoint
|
|
41
|
+
# - `DEFAULT_UA` for the User-Agent
|
|
42
|
+
# - `DEFAULT_PAGINATION` for the pagination handling class
|
|
43
|
+
#
|
|
44
|
+
# @example Reset the NinjaOne configuration:
|
|
45
|
+
# NinjaOne.reset
|
|
46
|
+
def self.reset
|
|
47
|
+
super
|
|
48
|
+
self.user_agent = DEFAULT_UA
|
|
49
|
+
end
|
|
50
|
+
end
|
data/ninjaone.gemspec
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/ninjaone/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'ninjaone'
|
|
7
|
+
s.version = NinjaOne::VERSION
|
|
8
|
+
s.authors = ['Janco Tanis']
|
|
9
|
+
s.email = 'gems@jancology.com'
|
|
10
|
+
s.license = 'MIT'
|
|
11
|
+
|
|
12
|
+
s.summary = 'A Ruby wrapper for the Skykick backup Portal REST APIs (readonly)'
|
|
13
|
+
s.homepage = 'https://rubygems.org/gems/skykick'
|
|
14
|
+
|
|
15
|
+
s.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
|
|
16
|
+
|
|
17
|
+
s.metadata['homepage_uri'] = s.homepage
|
|
18
|
+
s.metadata['source_code_uri'] = 'https://github.com/jancotanis/ninjaone'
|
|
19
|
+
|
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
22
|
+
s.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
24
|
+
end
|
|
25
|
+
s.bindir = 'exe'
|
|
26
|
+
s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
27
|
+
s.require_paths = ['lib']
|
|
28
|
+
|
|
29
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
30
|
+
s.platform = Gem::Platform::RUBY
|
|
31
|
+
s.add_runtime_dependency 'faraday'
|
|
32
|
+
s.add_runtime_dependency 'wrapi', ">= 0.4.0"
|
|
33
|
+
s.add_development_dependency 'dotenv'
|
|
34
|
+
s.add_development_dependency 'minitest'
|
|
35
|
+
s.add_development_dependency 'rubocop'
|
|
36
|
+
s.add_development_dependency 'simplecov'
|
|
37
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ninjaone
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Janco Tanis
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2025-12-10 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: faraday
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: wrapi
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 0.4.0
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 0.4.0
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: dotenv
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: minitest
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rubocop
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: simplecov
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
email: gems@jancology.com
|
|
97
|
+
executables: []
|
|
98
|
+
extensions: []
|
|
99
|
+
extra_rdoc_files: []
|
|
100
|
+
files:
|
|
101
|
+
- ".env.template"
|
|
102
|
+
- ".gitignore"
|
|
103
|
+
- CHANGELOG.md
|
|
104
|
+
- Gemfile
|
|
105
|
+
- README.md
|
|
106
|
+
- Rakefile
|
|
107
|
+
- lib/ninjaone.rb
|
|
108
|
+
- lib/ninjaone/api.rb
|
|
109
|
+
- lib/ninjaone/authentication.rb
|
|
110
|
+
- lib/ninjaone/client.rb
|
|
111
|
+
- lib/ninjaone/client/organizations.rb
|
|
112
|
+
- lib/ninjaone/client/system.rb
|
|
113
|
+
- lib/ninjaone/error.rb
|
|
114
|
+
- lib/ninjaone/version.rb
|
|
115
|
+
- ninjaone.gemspec
|
|
116
|
+
homepage: https://rubygems.org/gems/skykick
|
|
117
|
+
licenses:
|
|
118
|
+
- MIT
|
|
119
|
+
metadata:
|
|
120
|
+
homepage_uri: https://rubygems.org/gems/skykick
|
|
121
|
+
source_code_uri: https://github.com/jancotanis/ninjaone
|
|
122
|
+
rdoc_options: []
|
|
123
|
+
require_paths:
|
|
124
|
+
- lib
|
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - ">="
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: 2.4.0
|
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
|
+
requirements:
|
|
132
|
+
- - ">="
|
|
133
|
+
- !ruby/object:Gem::Version
|
|
134
|
+
version: '0'
|
|
135
|
+
requirements: []
|
|
136
|
+
rubygems_version: 3.6.2
|
|
137
|
+
specification_version: 4
|
|
138
|
+
summary: A Ruby wrapper for the Skykick backup Portal REST APIs (readonly)
|
|
139
|
+
test_files: []
|