ninjaone 0.2.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: d2d9edce18fc48c11d1eee0a7d87d4e3d23f3622c54d522495181f50f2004bb3
4
- data.tar.gz: a99415651e31f4616c478871acc3539abdcc16d452f372a366cdc321be9ed939
3
+ metadata.gz: 14e3e9d7389ec68d56ab1289d050a76c4287c223dec960df4201f236c7d24632
4
+ data.tar.gz: b78f6990641e9782d5033f9b2c4940fcb8e0464ba8c89ab01c7905bd54aca54e
5
5
  SHA512:
6
- metadata.gz: 13fe05ba9d907d7ebb217cdd79dd890e008a5805319e2de4bbcaba6a28d8f5a8f33cbed562f36797d081f823006553bbbdb4815a119a0678461b2b89bfaa5d5e
7
- data.tar.gz: 4481305a4e29b2dc3e3043e05a383225790f0c745d10efcfbe5dc06368e34b5a3d0e7fed9c43c469dd27304276f6ed25f496cfafdce317c2b65c00ba36377bbb
6
+ metadata.gz: 6ae0f84a5385fcff884d4de3830c9089bca742d8f8f8ba641e41d91231bb365cb9b800cb391ca7da2729c7be7bbbb265975dbbae11101b5bc74f69907ab828d0
7
+ data.tar.gz: df9bff698081312e3c1d11f4b319f554f3d091f02c34c5ad23eb20d4793f00883dec12269d55c3e3ec072ef5a4499263f8faea2b535c1ddcbe93fa4a88849824
data/CHANGELOG.md CHANGED
@@ -8,3 +8,12 @@
8
8
 
9
9
  - Added backup and devices api group
10
10
 
11
+ ## [0.2.1] - 2026-1-16
12
+
13
+ - Simplify api endpoint definition
14
+
15
+ ## [0.3.0] - 2026-1-19
16
+
17
+ - Implement (cursor) paging
18
+ - Support Group, Location, Queries, Users API
19
+
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  This is a wrapper for the ninjaone API.
6
6
  You can see the [API endpoints](https://app.ninjarmm.com/apidocs/)
7
7
 
8
- Currently only the GET requests to endpoints
8
+ Currently only the GET requests to endpoints
9
9
  are implemented (readonly).
10
10
 
11
11
  ## Installation
@@ -66,100 +66,168 @@ client.login
66
66
 
67
67
  |Resource|API endpoint|
68
68
  |:--|:--|
69
- |.auth_token or .login|https://app.ninjarmm.com/apidocs/?links.active=authorization|
69
+ |`login`|https://app.ninjarmm.com/apidocs/?links.active=authorization|
70
70
 
71
71
  ### System
72
72
 
73
73
  Core system Entities and Resources
74
74
 
75
75
  ```ruby
76
- subscriptions = client.subscriptions
76
+ client.organizations
77
+ client.devices
78
+ client.contacts
77
79
  ```
78
80
 
79
- |Resource|API endpoint|
81
+ |Method|Description|
80
82
  |:--|:--|
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|
83
+ |`contacts(params = {})`|List all contacts|
84
+ |`contact(id, params = {})`|Retrieve a specific contact by ID|
85
+ |`organizations(params = {})`|List all organizations|
86
+ |`organization(id, params = {})`|Retrieve a specific organization by ID|
87
+ |`organizations_detailed(params = {})`|List all organizations with detailed information|
88
+ |`policies(params = {})`|List all policies|
89
+ |`jobs(params = {})`|List all active jobs|
90
+ |`activities(params = {})`|List all activities|
91
+ |`alerts(params = {})`|List all active alerts (triggered conditions)|
92
+ |`automation_scripts(params = {})`|List available automation scripts|
93
+ |`devices(params = {})`|List all devices|
94
+ |`devices_detailed(params = {})`|List all devices with detailed information|
95
+ |`notification_channels_enabled(params = {})`|List enabled notification channels|
96
+ |`notification_channels(params = {})`|List all notification channels|
97
+ |`groups(params = {})`|List all groups (saved searches)|
98
+ |`locations(params = {})`|List all locations|
99
+ |`roles(params = {})`|List device roles|
100
+ |`tasks(params = {})`|List scheduled tasks|
101
+ |`software_products(params = {})`|List supported 3rd party software|
102
+ |`users(params = {})`|List all users|
103
+ |`user_end_users(params = {})`|List end users|
104
+ |`user_technicians(params = {})`|List technicians|
105
+ |`user_roles(params = {})`|Get user roles|
106
+ |`devices_search(params = {})`|Search devices by query parameter `q`|
107
+ |`search_devices(query_string, options = {})`|Helper method to search devices (equivalent to `devices_search({q: query_string})`)|
104
108
 
105
109
  ### Organizations
106
110
 
107
- All apis related to organizations
111
+ All APIs related to organizations
108
112
 
109
113
  ```ruby
110
- org = client.organizations.first
111
- org_devices = client.organization_devices(org.id)
112
-
114
+ organizations = client.organizations
115
+ org_id = organizations.first.id
116
+ org_devices = client.organization_devices(org_id)
113
117
  ```
114
118
 
115
- |Resource|API endpoint|
119
+ |Method|Description|
116
120
  |:--|:--|
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|
121
+ |`organization(id, params = {})`|Retrieve a specific organization by ID|
122
+ |`organization_locations(id, params = {})`|List all locations for the specified organization|
123
+ |`organization_end_users(id, params = {})`|List all end users in the specified organization|
124
+ |`organization_custom_fields(id, params = {})`|Retrieve custom fields for the specified organization|
125
+ |`organization_devices(id, params = {})`|List all devices in the specified organization|
126
+ |`organization_locations_backup_usage(id, params = {})`|Retrieve backup usage for all locations in the specified organization|
127
+ |`organization_backup_usage_by_location(id, location_id, params = {})`|Retrieve backup usage for a specific location in the specified organization|
128
+ |`organization_location_custom_fields(id, location_id, params = {})`|Retrieve custom fields for a specific location in the specified organization|
124
129
 
125
130
  ### Backup
126
131
 
127
- All apis related to backup
132
+ All APIs related to backup
128
133
 
129
134
  ```ruby
130
- # get failed jobs using status filter
131
- failed_jobs = client.backup_jobs(sf:'status = FAILED')
135
+ # Get failed jobs using status filter
136
+ failed_jobs = client.backup_jobs(sf: 'status = FAILED')
137
+ integrity_jobs = client.backup_integrity_checks_jobs
132
138
  ```
133
139
 
134
- |Resource|API endpoint|
140
+ |Method|Description|
135
141
  |:--|:--|
136
- |`backup_jobs(params)`|Returns list of backup jobs. Params is a hash for filtering the result|
137
- |`backup_integrity_check_jobs(params)`|Returns a list of integrity check jobs|
142
+ |`backup_jobs(params = {})`|List all backup jobs. Supports filtering via `sf` (filter) and `sc` (sort) parameters|
143
+ |`backup_integrity_checks_jobs(params = {})`|List all backup integrity check jobs. Supports filtering and sorting parameters|
138
144
 
139
145
  ### Devices
140
146
 
141
- All apis related to devices.
147
+ All APIs related to devices
148
+
149
+ ```ruby
150
+ device = client.device(12345)
151
+ device_jobs = client.device_jobs(12345)
152
+ device_activities = client.device_activities(12345, since: '2026-01-01T00:00:00Z')
153
+ group_device_ids = client.group_device_ids(group_id)
154
+ ```
142
155
 
143
- | Resource | API endpoint |
156
+ |Method|Description|
144
157
  |:--|:--|
145
- | `device(id, params = {})` | Retrieves the details of a single device by its device ID. |
146
- | `device_jobs(id, params = {})` | Retrieves all jobs associated with the specified device. |
147
- | `device_activities(id, params = {})` | Retrieves activities for the specified device (e.g. filtered using `since`). |
148
- | `device_alerts(id, params = {})` | Retrieves alerts related to the specified device. |
149
- | `device_disks(id, params = {})` | Retrieves disk information for the specified device. |
150
- | `device_processors(id, params = {})` | Retrieves processor information for the specified device. |
151
- | `device_software(id, params = {})` | Retrieves installed software for the specified device. |
152
- | `device_volumes(id, params = {})` | Retrieves volume information for the specified device. |
153
- | `device_windows_services(id, params = {})` | Retrieves Windows services for the specified device. |
154
- | `device_custom_fields(id, params = {})` | Retrieves custom fields associated with the specified device. |
155
- | `device_os_patch_installs(id, params = {})` | Retrieves operating system patch installation records for the specified device. |
156
- | `device_software_patch_installs(id, params = {})` | Retrieves software patch installation records for the specified device. |
157
- | `device_last_logged_on_user(id, params = {})` | Retrieves information about the last logged-on user of the device. |
158
- | `device_network_interfaces(id, params = {})` | Retrieves network interface information for the specified device. |
159
- | `device_os_patches(id, params = {})` | Retrieves available or installed operating system patches for the device. |
160
- | `device_software_patches(id, params = {})` | Retrieves available or installed software patches for the device. |
161
- | `device_policy_overrides(id, params = {})` | Retrieves policy overrides applied to the specified device. |
158
+ |`device(id, params = {})`|Retrieve details of a single device by its device ID|
159
+ |`device_policy_overrides(id, params = {})`|Retrieve policy overrides applied to the specified device|
160
+ |`device_jobs(id, params = {})`|Retrieve all jobs associated with the specified device|
161
+ |`device_activities(id, params = {})`|Retrieve activities for the specified device (supports `since` filtering)|
162
+ |`device_alerts(id, params = {})`|Retrieve alerts related to the specified device|
163
+ |`device_disks(id, params = {})`|Retrieve disk information for the specified device|
164
+ |`device_processors(id, params = {})`|Retrieve processor information for the specified device|
165
+ |`device_software(id, params = {})`|Retrieve installed software for the specified device|
166
+ |`device_volumes(id, params = {})`|Retrieve volume information for the specified device|
167
+ |`device_windows_services(id, params = {})`|Retrieve Windows services for the specified device|
168
+ |`device_custom_fields(id, params = {})`|Retrieve custom fields associated with the specified device|
169
+ |`device_os_patch_installs(id, params = {})`|Retrieve operating system patch installation records for the specified device|
170
+ |`device_software_patch_installs(id, params = {})`|Retrieve software patch installation records for the specified device|
171
+ |`device_last_logged_on_user(id, params = {})`|Retrieve information about the last logged-on user of the device|
172
+ |`device_network_interfaces(id, params = {})`|Retrieve network interface information for the specified device|
173
+ |`device_os_patches(id, params = {})`|Retrieve available or installed operating system patches for the device|
174
+ |`device_software_patches(id, params = {})`|Retrieve available or installed software patches for the device|
175
+ |`group_device_ids(id, params = {})`|Retrieve device IDs for all devices in the specified group|
176
+
177
+ ### Users
178
+
179
+ All APIs related to user management
180
+
181
+ ```ruby
182
+ end_user = client.user_end_user(end_user_id)
183
+ end_user_custom_fields = client.user_end_user_custom_fields(end_user_id)
184
+ technician = client.user_technician(technician_id)
185
+ ```
162
186
 
187
+ |Method|Description|
188
+ |:--|:--|
189
+ |`user_end_user(id, params = {})`|Retrieve details of a specific end user|
190
+ |`user_end_user_custom_fields(id, params = {})`|Retrieve custom fields for a specific end user|
191
+ |`user_technician(id, params = {})`|Retrieve details of a specific technician|
192
+
193
+ ### Queries
194
+
195
+ Query endpoints that support pagination for advanced data retrieval
196
+
197
+ ```ruby
198
+ av_status = client.queries_antivirus_status
199
+ device_health = client.queries_device_health
200
+ software_list = client.queries_software
201
+ ```
202
+
203
+ All query methods support pagination and filtering parameters. Query methods return paginated results.
204
+
205
+ |Method|Description|
206
+ |:--|:--|
207
+ |`queries_antivirus_status(params = {})`|Query antivirus status across devices|
208
+ |`queries_antivirus_threats(params = {})`|Query antivirus threats across devices|
209
+ |`queries_computer_systems(params = {})`|Query computer system information|
210
+ |`queries_custom_fields_detailed(params = {})`|Query custom fields with detailed information|
211
+ |`queries_custom_fields(params = {})`|Query custom fields|
212
+ |`queries_device_health(params = {})`|Query device health status|
213
+ |`queries_backup_usage(params = {})`|Query backup usage across devices|
214
+ |`queries_disks(params = {})`|Query disk information|
215
+ |`queries_os_patch_installs(params = {})`|Query operating system patch installations|
216
+ |`queries_software_patch_installs(params = {})`|Query software patch installations|
217
+ |`queries_logged_on_users(params = {})`|Query currently logged-on users|
218
+ |`queries_network_interfaces(params = {})`|Query network interface information|
219
+ |`queries_operating_systems(params = {})`|Query operating system information|
220
+ |`queries_os_patches(params = {})`|Query operating system patches|
221
+ |`queries_software_patches(params = {})`|Query software patches|
222
+ |`queries_policy_overrides(params = {})`|Query policy overrides|
223
+ |`queries_processors(params = {})`|Query processor information|
224
+ |`queries_raid_controllers(params = {})`|Query RAID controller information|
225
+ |`queries_raid_drives(params = {})`|Query RAID drive information|
226
+ |`queries_scoped_custom_fields_detailed(params = {})`|Query scoped custom fields with detailed information|
227
+ |`queries_scoped_custom_fields(params = {})`|Query scoped custom fields|
228
+ |`queries_software(params = {})`|Query software information|
229
+ |`queries_volumes(params = {})`|Query volume information|
230
+ |`queries_windows_services(params = {})`|Query Windows services|
163
231
 
164
232
  ## Contributing
165
233
 
@@ -6,32 +6,10 @@ module NinjaOne
6
6
  #
7
7
  # @see https://app.ninjarmm.com/apidocs/?links.active=core#/Backup Ninja One Developer Documentation - Backup section
8
8
  module Backup
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 path [String] The API path for the resource. Defaults to the method name.
17
- #
18
- # @example Defining endpoints
19
- # api_endpoint :companies, :company
20
- # # Defines:
21
- # # - `companies(params = {})` to fetch all companies.
22
- # # - `company(id, params = {})` to fetch a single company by ID.
23
- def self.backup_endpoint(method, path = method.to_s.tr('_', '-'))
24
- # Define method to fetch all records
25
- send(:define_method, method) do |params = {}|
26
- results = get(api_url(path), params)
27
- results.results
28
- end
29
- end
30
9
 
31
10
  # Backup endpoints (GET)
32
- backup_endpoint(:backup_jobs, 'backup/jobs')
33
- backup_endpoint(:backup_integrity_check_jobs, 'backup/integrity-check-jobs')
34
-
11
+ Client::define_endpoint('backup/jobs', nil, true)
12
+ Client::define_endpoint('backup/integrity-check-jobs', nil, true)
35
13
  end
36
14
  end
37
15
  end
@@ -2,47 +2,14 @@
2
2
 
3
3
  module NinjaOne
4
4
  class Client
5
- # Contains Device-related API calls for Ninja One.
5
+ # Contains Device and group related API calls for Ninja One.
6
6
  #
7
7
  # @see https://app.ninjarmm.com/apidocs/?links.active=core#/Devices Ninja One Developer Documentation - Device section
8
8
  module Devices
9
- # Defines a device-specific API endpoint method dynamically.
10
- #
11
- # This helper creates instance methods in the form of:
12
- # device_<method>(id, params = {})
13
- #
14
- # Example:
15
- # device_endpoint(:jobs)
16
- # # => defines #device_jobs(id, params = {})
17
- #
18
- # @param method [Symbol]
19
- # The method name suffix to generate (e.g., :jobs, :alerts).
20
- #
21
- # @param path [String]
22
- # The API path segment. Defaults to the method name with
23
- # underscores replaced by hyphens.
24
- #
25
- # @return [void]
26
- def self.device_endpoint(method, path = method.to_s.tr('_', '-'))
27
- # Define method to fetch all records for device
28
- send(:define_method, "device_#{method}") do |id, params = {}|
29
- get(api_url("device/#{id}/#{path}"), params)
30
- end
31
- end
32
9
 
33
- # Retrieves a single device by ID.
34
- #
35
- # @param id [Integer, String]
36
- # The NinjaOne device ID.
37
- #
38
- # @param params [Hash, nil]
39
- # Optional query parameters.
40
- #
41
- # @return [Hash]
42
- # The device details returned by the API.
43
- def device(id, params = nil)
44
- get(api_url("device/#{id}"), params)
45
- end
10
+ Client::define_endpoint(:device, '')
11
+ Client::define_endpoint(:device, 'policy/overrides')
12
+ Client::define_endpoint(:group, 'device-ids')
46
13
 
47
14
  # Device-related GET endpoints.
48
15
  #
@@ -54,10 +21,9 @@ module NinjaOne
54
21
  # device_activities(123, since: '2026-01-01T00:00:00Z')
55
22
  #
56
23
  [:jobs, :activities, :alerts, :disks, :processors, :software, :volumes, :windows_services, :custom_fields,
57
- :os_patch_installs, :software_patch_installs, :last_logged_on_user, :network_interfaces, :os_patches, :software_patches].each do |m|
58
- device_endpoint(m)
24
+ :os_patch_installs, :software_patch_installs, :last_logged_on_user, :network_interfaces, :os_patches, :software_patches].each do |resource|
25
+ Client::define_endpoint(:device, resource.to_s.gsub('_','-'))
59
26
  end
60
- device_endpoint(:policy_overrides, 'policy/overrides')
61
27
  end
62
28
  end
63
29
  end
@@ -2,47 +2,28 @@
2
2
 
3
3
  module NinjaOne
4
4
  class Client
5
- # Contains Organizations API calls for Ninja One.
5
+ # Contains Organizations and location API calls for Ninja One.
6
6
  #
7
7
  # @see https://app.ninjarmm.com/apidocs/?links.active=core#/organization Ninja One Developer Documentation
8
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
9
 
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')
10
+ Client::define_endpoint(:organization, 'locations')
11
+ Client::define_endpoint(:organization, 'end-users')
12
+ Client::define_endpoint(:organization, 'custom-fields')
13
+ Client::define_endpoint(:organization, 'devices')
14
+ Client::define_endpoint(:organization, 'locations/backup/usage')
38
15
 
39
16
  # Returns a location backup usage
40
17
  def organization_backup_usage_by_location(id, location_id, params={})
41
18
  get(api_url("organization/#{id}/locations/#{location_id}/backup/usage"), params)
42
19
  rescue Faraday::ServerError
43
- # it looks like a server error is thrown when no backup is available; fake it by returning anempty array
20
+ # it looks like a server error is thrown when no backup is available; fake it by returning an empty array
44
21
  []
45
22
  end
23
+ # Returns custom fields for an organization location
24
+ def organization_location_custom_fields(id, location_id, params={})
25
+ get(api_url("organization/#{id}/location/#{location_id}/custom-fields"), params)
26
+ end
46
27
  end
47
28
  end
48
29
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NinjaOne
4
+ class Client
5
+ # Contains Queries API calls for Ninja One.
6
+ #
7
+ # @see https://app.ninjarmm.com/apidocs/?links.active=core#/queries Ninja One Developer Documentation
8
+ module Queries
9
+ Client::define_endpoint('queries/antivirus-status', nil, true)
10
+ Client::define_endpoint('queries/antivirus-threats', nil, true)
11
+ Client::define_endpoint('queries/computer-systems', nil, true)
12
+ Client::define_endpoint('queries/custom-fields-detailed', nil, true)
13
+ Client::define_endpoint('queries/custom-fields', nil, true)
14
+ Client::define_endpoint('queries/device-health', nil, true)
15
+ Client::define_endpoint('queries/backup/usage', nil, true)
16
+ Client::define_endpoint('queries/disks', nil, true)
17
+ Client::define_endpoint('queries/os-patch-installs', nil, true)
18
+ Client::define_endpoint('queries/software-patch-installs', nil, true)
19
+ Client::define_endpoint('queries/logged-on-users', nil, true)
20
+ Client::define_endpoint('queries/network-interfaces', nil, true)
21
+ Client::define_endpoint('queries/operating-systems', nil, true)
22
+ Client::define_endpoint('queries/os-patches', nil, true)
23
+ Client::define_endpoint('queries/software-patches', nil, true)
24
+ Client::define_endpoint('queries/policy-overrides', nil, true)
25
+ Client::define_endpoint('queries/processors', nil, true)
26
+ Client::define_endpoint('queries/raid-controllers', nil, true)
27
+ Client::define_endpoint('queries/raid-drives', nil, true)
28
+ Client::define_endpoint('queries/scoped-custom-fields-detailed', nil, true)
29
+ Client::define_endpoint('queries/scoped-custom-fields', nil, true)
30
+ Client::define_endpoint('queries/software', nil, true)
31
+ Client::define_endpoint('queries/volumes', nil, true)
32
+ Client::define_endpoint('queries/windows-services', nil, true)
33
+ end
34
+ end
35
+ end
@@ -7,28 +7,30 @@ module NinjaOne
7
7
  # @see https://app.ninjarmm.com/apidocs/?links.active=core#/system Ninja One Developer Documentation
8
8
  module System
9
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')
10
+ Client::define_endpoint(:contacts)
11
+ Client::define_endpoint(:contact, '')
12
+ Client::define_endpoint(:organizations)
13
+ Client::define_endpoint(:organization, '')
14
+ Client::define_endpoint('organizations-detailed')
15
+ Client::define_endpoint(:policies)
16
+ Client::define_endpoint(:jobs)
17
+ Client::define_endpoint(:activities)
18
+ Client::define_endpoint(:alerts)
19
+ Client::define_endpoint('automation/scripts')
20
+ Client::define_endpoint(:devices)
21
+ Client::define_endpoint('devices-detailed')
22
+ Client::define_endpoint('notification-channels/enabled')
23
+ Client::define_endpoint('notification-channels')
24
+ Client::define_endpoint(:groups)
25
+ Client::define_endpoint(:locations)
26
+ Client::define_endpoint(:roles)
27
+ Client::define_endpoint(:tasks)
28
+ Client::define_endpoint('software-products')
29
+ Client::define_endpoint(:users)
30
+ Client::define_endpoint('user/end-users')
31
+ Client::define_endpoint('user/roles')
32
+ Client::define_endpoint('user/technicians')
33
+ Client::define_endpoint('devices/search')
32
34
 
33
35
  def search_devices(query_string, options={})
34
36
  devices_search(options.merge({q:query_string}))
@@ -0,0 +1,15 @@
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#/users Ninja One Developer Documentation
8
+ module Users
9
+
10
+ Client::define_endpoint('user/end-user', '')
11
+ Client::define_endpoint('user/end-user', 'custom-fields')
12
+ Client::define_endpoint('user/technician', '')
13
+ end
14
+ end
15
+ end
@@ -9,34 +9,52 @@ module NinjaOne
9
9
  # @note All methods are grouped in separate modules for better organization and follow the structure provided in the official API documentation.
10
10
  # @see https://developers.skykick.com/Guides/Authentication
11
11
  class Client < API
12
+
13
+ # Constructs url resource name from url path
14
+ #
15
+ # @param path [String] Resource name
16
+ # @return [String] translated from /- to _
17
+ def self.resource_to_name(path)
18
+ path.to_s.gsub(/[-\/]/,'_')
19
+ end
20
+
12
21
  # Dynamically defines methods for interacting with NinjaOne API resources.
13
22
  #
14
23
  # Depending on the arguments, this will define methods to:
15
- # - Fetch all records for a resource
16
- # - Fetch a specific record by ID
24
+ # - Fetch all records for the given scope
25
+ # - Fetch a resource specific record by ID
26
+ #
27
+ # @param scope [Symbol] The method name for fetching all records.
28
+ # @param resource [String] If given, fetches all records for scope by id. If empty string, it will load single scope record
17
29
  #
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.
30
+ # Paging is not supported.
21
31
  #
22
32
  # @example Defining endpoints
23
33
  # api_endpoint :companies, :company
24
34
  # # Defines:
25
35
  # # - `companies(params = {})` to fetch all companies.
26
36
  # # - `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)
37
+ def self.define_endpoint(scope, resource = nil, paged = false)
38
+ if resource
39
+ name = self.resource_to_name(scope)
40
+ name = "#{name}_#{self.resource_to_name(resource)}" if resource && !resource.empty?
41
+ # change to nil if resource is empty so we ar eable to generate /scope/id/resource
42
+ # but also /scope/id without training /
43
+ resource = resource&.empty? ? nil : resource
44
+ send(:define_method, name) do |id, params = {}|
45
+ url = api_url([scope, id, resource].compact.join('/'))
46
+ paged ? get_paged(url, params) : get(url, params)
47
+ end
48
+ else
49
+ name = self.resource_to_name(scope)
50
+ send(:define_method, name) do |params = {}|
51
+ url = api_url(scope)
52
+ paged ? get_paged(url, params) : get(url, params)
36
53
  end
37
54
  end
38
55
  end
39
56
 
57
+
40
58
  # Dynamically require all files in the `client` directory.
41
59
  # This will load additional API modules as separate files for better modularity and code organization.
42
60
  Dir[File.expand_path('client/*.rb', __dir__)].each { |f| require f }
@@ -48,6 +66,8 @@ module NinjaOne
48
66
  include NinjaOne::Client::Organizations
49
67
  include NinjaOne::Client::Backup
50
68
  include NinjaOne::Client::Devices
69
+ include NinjaOne::Client::Users
70
+ include NinjaOne::Client::Queries
51
71
 
52
72
  # Constructs the full API URL for a given path.
53
73
  #
@@ -56,6 +76,5 @@ module NinjaOne
56
76
  def api_url(path)
57
77
  "/v2/#{path}"
58
78
  end
59
-
60
79
  end
61
80
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'json'
5
+
6
+ module NinjaOne
7
+ # Defines HTTP request pagination methods for NinjOne API.
8
+ # This module handles the pagination strategy required when dealing with paginated
9
+ # API results. NinjaOne uses Cursor pagination, in combination with `cursor` and `pageSize` parameter
10
+ module RequestPagination
11
+ # Maintains pagination state for cursor-based endpoints.
12
+ #
13
+ # NinjaOne returns payloads like:
14
+ # {
15
+ # "cursor": { "name": "string", "offset": 0, "count": 0, "expires": 0 },
16
+ # "results": []
17
+ # }
18
+ #
19
+ # @example Pagination Initialization
20
+ # paginator = NinjaOne::RequestPagination::CursorPagination.new(100)
21
+ # options = paginator.page_options # => { pageSize: 100 }
22
+ #
23
+ # @see https://app.ninjarmm.com/apidocs/?links.active=core#/queries/getAntivirusStatusReport
24
+ class CursorPagination
25
+ attr_reader :offset, :limit, :total
26
+
27
+ # Initializes the pagination object with the specified page size.
28
+ # Assumes that pagination starts at the first page (offset 0).
29
+ #
30
+ # @param page_size [Integer] Number of results per page
31
+ def initialize(page_size)
32
+ @offset = 0
33
+ @cursor = nil
34
+ @limit = page_size
35
+ # Assume at least one page initially (used to short-circuit more_pages? after last page)
36
+ @total = @limit
37
+ end
38
+
39
+ # Returns the pagination options to be sent as query parameters.
40
+ # If a cursor is present, it will be included to fetch the next page.
41
+ #
42
+ # @return [Hash<Symbol, Integer|String>] Query parameters for pagination
43
+ def page_options
44
+ {
45
+ pageSize: @limit,
46
+ cursor: @cursor
47
+ }.compact
48
+ end
49
+
50
+ # Updates the pagination state for the next page based on the current page's data.
51
+ # The NinjaOne API does not allow skipping
52
+ #
53
+ # @param data [Hash] The data from the current page
54
+ def next_page!(data)
55
+ # Update the total number of results based on the size of the current data set.
56
+ if cursor = data['cursor']
57
+ @total = cursor['count']
58
+ @offset = cursor['offset']
59
+ @cursor = cursor['name']
60
+ else
61
+ # no cursor, then we're ready
62
+ @offset = @total
63
+ end
64
+ end
65
+
66
+ # Processes the API response body and returns it unchanged.
67
+ # This method can be overridden to handle specific response parsing needs.
68
+ #
69
+ # @param body [Hash, Array, String] The response body from the API
70
+ # @return [Hash, Array, String] Processed data (unchanged)
71
+ def self.data(body)
72
+ return body if body.is_a?(Array)
73
+ body['results'] || body
74
+ end
75
+
76
+ # Checks if more pages are available.
77
+ # More pages are available if the data has cursor records or if we just start with getting the first page.
78
+ #
79
+ # @return [Boolean] `true` if more pages are available, `false` otherwise
80
+ def more_pages?
81
+ @offset.zero? || @offset < @total
82
+ end
83
+ end
84
+ end
85
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NinjaOne
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/ninjaone.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'wrapi'
4
4
  require File.expand_path('ninjaone/api', __dir__)
5
+ require File.expand_path('ninjaone/cursor_pagination', __dir__)
5
6
  require File.expand_path('ninjaone/client', __dir__)
6
7
  require File.expand_path('ninjaone/version', __dir__)
7
8
 
@@ -15,6 +16,7 @@ module NinjaOne
15
16
 
16
17
  # Default User-Agent header sent with API requests, including gem version information.
17
18
  DEFAULT_UA = "NinjaOne Ruby API wrapper #{NinjaOne::VERSION}"
19
+ DEFAULT_PAGINATION = RequestPagination::CursorPagination
18
20
 
19
21
  # Creates and returns a new NinjaOne API client with the given options.
20
22
  #
@@ -30,7 +32,8 @@ module NinjaOne
30
32
  # client = NinjaOne.client(endpoint: "https://api.custom-endpoint.com", user_agent: "Custom UA/1.0")
31
33
  def self.client(options = {})
32
34
  NinjaOne::Client.new({
33
- user_agent: DEFAULT_UA
35
+ user_agent: DEFAULT_UA,
36
+ pagination_class: DEFAULT_PAGINATION
34
37
  }.merge(options))
35
38
  end
36
39
 
@@ -46,5 +49,6 @@ module NinjaOne
46
49
  def self.reset
47
50
  super
48
51
  self.user_agent = DEFAULT_UA
52
+ self.pagination_class = DEFAULT_PAGINATION
49
53
  end
50
54
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ninjaone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janco Tanis
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-01-15 00:00:00.000000000 Z
10
+ date: 2026-01-19 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: faraday
@@ -111,7 +111,10 @@ files:
111
111
  - lib/ninjaone/client/backup.rb
112
112
  - lib/ninjaone/client/devices.rb
113
113
  - lib/ninjaone/client/organizations.rb
114
+ - lib/ninjaone/client/queries.rb
114
115
  - lib/ninjaone/client/system.rb
116
+ - lib/ninjaone/client/users.rb
117
+ - lib/ninjaone/cursor_pagination.rb
115
118
  - lib/ninjaone/error.rb
116
119
  - lib/ninjaone/version.rb
117
120
  - ninjaone.gemspec