ruby-jss 0.6.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-jss might be problematic. Click here for more details.

Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +7 -0
  3. data/CHANGES.md +112 -0
  4. data/LICENSE.txt +174 -0
  5. data/README.md +426 -0
  6. data/THANKS.md +6 -0
  7. data/bin/cgrouper +485 -0
  8. data/bin/subnet-update +400 -0
  9. data/lib/jss-api.rb +2 -0
  10. data/lib/jss.rb +190 -0
  11. data/lib/jss/api_connection.rb +410 -0
  12. data/lib/jss/api_object.rb +616 -0
  13. data/lib/jss/api_object/advanced_search.rb +389 -0
  14. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
  15. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
  16. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
  17. data/lib/jss/api_object/building.rb +92 -0
  18. data/lib/jss/api_object/category.rb +147 -0
  19. data/lib/jss/api_object/computer.rb +852 -0
  20. data/lib/jss/api_object/creatable.rb +98 -0
  21. data/lib/jss/api_object/criteriable.rb +189 -0
  22. data/lib/jss/api_object/criteriable/criteria.rb +231 -0
  23. data/lib/jss/api_object/criteriable/criterion.rb +228 -0
  24. data/lib/jss/api_object/department.rb +93 -0
  25. data/lib/jss/api_object/distribution_point.rb +560 -0
  26. data/lib/jss/api_object/extendable.rb +221 -0
  27. data/lib/jss/api_object/extension_attribute.rb +466 -0
  28. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
  29. data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
  30. data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
  31. data/lib/jss/api_object/group.rb +380 -0
  32. data/lib/jss/api_object/group/computer_group.rb +124 -0
  33. data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
  34. data/lib/jss/api_object/group/user_group.rb +139 -0
  35. data/lib/jss/api_object/ldap_server.rb +535 -0
  36. data/lib/jss/api_object/locatable.rb +286 -0
  37. data/lib/jss/api_object/matchable.rb +97 -0
  38. data/lib/jss/api_object/mobile_device.rb +556 -0
  39. data/lib/jss/api_object/netboot_server.rb +148 -0
  40. data/lib/jss/api_object/network_segment.rb +414 -0
  41. data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
  42. data/lib/jss/api_object/package.rb +839 -0
  43. data/lib/jss/api_object/peripheral.rb +335 -0
  44. data/lib/jss/api_object/peripheral_type.rb +295 -0
  45. data/lib/jss/api_object/policy.rb +898 -0
  46. data/lib/jss/api_object/purchasable.rb +316 -0
  47. data/lib/jss/api_object/removable_macaddr.rb +98 -0
  48. data/lib/jss/api_object/scopable.rb +136 -0
  49. data/lib/jss/api_object/scopable/scope.rb +621 -0
  50. data/lib/jss/api_object/script.rb +631 -0
  51. data/lib/jss/api_object/self_servable.rb +356 -0
  52. data/lib/jss/api_object/site.rb +93 -0
  53. data/lib/jss/api_object/software_update_server.rb +109 -0
  54. data/lib/jss/api_object/updatable.rb +117 -0
  55. data/lib/jss/api_object/uploadable.rb +138 -0
  56. data/lib/jss/api_object/user.rb +272 -0
  57. data/lib/jss/client.rb +504 -0
  58. data/lib/jss/compatibility.rb +66 -0
  59. data/lib/jss/composer.rb +185 -0
  60. data/lib/jss/configuration.rb +306 -0
  61. data/lib/jss/db_connection.rb +298 -0
  62. data/lib/jss/exceptions.rb +95 -0
  63. data/lib/jss/ruby_extensions.rb +35 -0
  64. data/lib/jss/ruby_extensions/filetest.rb +43 -0
  65. data/lib/jss/ruby_extensions/hash.rb +79 -0
  66. data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
  67. data/lib/jss/ruby_extensions/pathname.rb +77 -0
  68. data/lib/jss/ruby_extensions/string.rb +59 -0
  69. data/lib/jss/ruby_extensions/time.rb +63 -0
  70. data/lib/jss/server.rb +108 -0
  71. data/lib/jss/utility.rb +478 -0
  72. data/lib/jss/version.rb +31 -0
  73. metadata +187 -0
@@ -0,0 +1,286 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Variables
30
+ #####################################
31
+
32
+ #####################################
33
+ ### Module Methods
34
+ #####################################
35
+
36
+ #####################################
37
+ ### Sub-Modules
38
+ #####################################
39
+
40
+ ### A mix-in module for handling location/user data for objects in the JSS.
41
+ ###
42
+ ### The JSS objects that have location data return it in a :location subset,
43
+ ### which all have basically the same data,a simple hash with these keys:
44
+ ### - :building => String,
45
+ ### - :department => String,
46
+ ### - :email_address => String,
47
+ ### - :phone => String
48
+ ### - :position => String
49
+ ### - :real_name => String,
50
+ ### - :room => String,
51
+ ### - :username => String
52
+ ###
53
+ ### Including this module in an {APIObject} subclass will give it attributes
54
+ ### matching those keys, which are populated by calling {#parse_location} in the
55
+ ### subclass's constructor after calling super.
56
+ ###
57
+ ### If the subclass is creatable or updatable, calling {#location_xml} returns
58
+ ### a REXML element representing the location subset, to be included with the
59
+ ### #rest_xml output of the subclass.
60
+ ###
61
+ module Locatable
62
+
63
+ #####################################
64
+ ### Constants
65
+ #####################################
66
+
67
+ LOCATABLE = true
68
+
69
+ #####################################
70
+ ### Variables
71
+ #####################################
72
+
73
+
74
+ #####################################
75
+ ### Attribtues
76
+ #####################################
77
+
78
+ ###
79
+ ### Objects with a Location subset have those values stored as
80
+ ### primary attributes here, not in a single Hash attribute
81
+ ### as the other subsets
82
+
83
+ ### @return [String]
84
+ attr_reader :building
85
+
86
+ ### @return [String]
87
+ attr_reader :department
88
+
89
+ ### @return [String]
90
+ attr_reader :email_address
91
+
92
+ ### @return [String]
93
+ attr_reader :phone
94
+
95
+ ### @return [String]
96
+ attr_reader :position
97
+
98
+ ### @return [String]
99
+ attr_reader :real_name
100
+
101
+ ### @return [String]
102
+ attr_reader :room
103
+
104
+ ### @return [String]
105
+ attr_reader :username
106
+
107
+
108
+ #####################################
109
+ ### Mixed-in Instance Methods
110
+ #####################################
111
+
112
+ ###
113
+ ### Call this during initialization of
114
+ ### objects that have a Location subset
115
+ ### and the location attributes will be populated
116
+ ### (as primary attributes) from @init_data
117
+ ###
118
+ ### @return [void]
119
+ ###
120
+ def parse_location
121
+ @init_data[:location] ||= {}
122
+ @building = @init_data[:location][:building]
123
+ @department = @init_data[:location][:department]
124
+ @email_address = @init_data[:location][:email_address]
125
+ @phone = @init_data[:location][:phone]
126
+ @position = @init_data[:location][:position]
127
+ @real_name = @init_data[:location][:real_name]
128
+ @room = @init_data[:location][:room]
129
+ @username = @init_data[:location][:username]
130
+ end
131
+
132
+
133
+ ###
134
+ ### All the location data in a Hash, as it comes from the API.
135
+ ###
136
+ ### The reason it isn't stored this way is to prevent editing of the hash directly.
137
+ ###
138
+ ### @return [Hash<String>] the location data
139
+ ###
140
+ def location
141
+ {
142
+ :building => @building,
143
+ :department => @department,
144
+ :email_address => @email_address,
145
+ :phone => @phone,
146
+ :position => @position,
147
+ :real_name => @real_name,
148
+ :room => @room,
149
+ :username => @username
150
+ }
151
+ end
152
+
153
+
154
+ ###
155
+ ###
156
+ ### Setters
157
+ ###
158
+
159
+ ###
160
+ def building= (new_val)
161
+ return nil if @building == new_val
162
+ new_val = new_val.to_s.strip
163
+ raise JSS::NoSuchItemError, "No building named #{new_val} exists in the JSS" unless new_val.empty? or JSS::Building.all_names.include? new_val
164
+ @building = new_val
165
+ @need_to_update = true
166
+ end
167
+
168
+ ###
169
+ def department= (new_val)
170
+ return nil if @department == new_val
171
+ new_val = new_val.to_s.strip
172
+ raise JSS::NoSuchItemError, "No department named #{new_val} exists in the JSS" unless new_val.empty? or JSS::Department.all_names.include? new_val
173
+ @department = new_val
174
+ @need_to_update = true
175
+ end
176
+
177
+ ###
178
+ def email_address= (new_val)
179
+ return nil if @email_address == new_val
180
+ new_val = new_val.to_s.strip
181
+ raise JSS::InvalidDataError, "Invalid Email Address" unless new_val.empty? or new_val =~ /^[^\s@]+@[^\s@]+$/
182
+ @email_address = new_val
183
+ @need_to_update = true
184
+ end
185
+
186
+ ###
187
+ def position= (new_val)
188
+ return nil if @position == new_val
189
+ new_val = new_val.to_s.strip
190
+ @position = new_val
191
+ @need_to_update = true
192
+ end
193
+
194
+ ###
195
+ def phone= (new_val)
196
+ return nil if @phone == new_val
197
+ new_val = new_val.to_s.strip
198
+ @phone = new_val
199
+ @need_to_update = true
200
+ end
201
+
202
+ ###
203
+ def real_name= (new_val)
204
+ return nil if @real_name == new_val
205
+ new_val = new_val.to_s.strip
206
+ @real_name = new_val
207
+ @need_to_update = true
208
+ end
209
+
210
+ ###
211
+ def room= (new_val)
212
+ return nil if @room == new_val
213
+ new_val = new_val.to_s.strip
214
+ @room = new_val
215
+ @need_to_update = true
216
+ end
217
+
218
+ ###
219
+ def username= (new_val)
220
+ return nil if @username == new_val
221
+ new_val = new_val.to_s.strip
222
+ @username = new_val
223
+ @need_to_update = true
224
+ end
225
+
226
+ ###
227
+ ### @return [Boolean] Does this item have location data?
228
+ ###
229
+ def has_location?
230
+ @username or \
231
+ @real_name or \
232
+ @email_address or \
233
+ @position or \
234
+ @phone or \
235
+ @department or \
236
+ @building or \
237
+ @room
238
+ end
239
+
240
+ ###
241
+ ### Clear all location data
242
+ ###
243
+ ### @return [void]
244
+ ###
245
+ def clear_location
246
+ @username = ''
247
+ @real_name = ''
248
+ @email_address = ''
249
+ @position = ''
250
+ @phone = ''
251
+ @department = ''
252
+ @building = ''
253
+ @room = ''
254
+ @need_to_update = true
255
+ end
256
+
257
+
258
+ ### aliases
259
+ alias user username
260
+
261
+
262
+ ###
263
+ ### @api private
264
+ ###
265
+ ### Return a REXML <location> element to be
266
+ ### included in the rest_xml of
267
+ ### objects that have a Location subset
268
+ ###
269
+ ### @return [REXML::Element]
270
+ ###
271
+ def location_xml
272
+ location = REXML::Element.new('location')
273
+ location.add_element('building').text = @building
274
+ location.add_element('department').text = @department
275
+ location.add_element('email_address').text = @email_address
276
+ location.add_element('position').text = @position
277
+ location.add_element('phone').text = @phone
278
+ location.add_element('real_name').text = @real_name
279
+ location.add_element('room').text = @room
280
+ location.add_element('username').text = @username
281
+ return location
282
+ end
283
+
284
+ end # module Locatable
285
+
286
+ end # module JSS
@@ -0,0 +1,97 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ ### A mix-in module providing access to the "match" resources for some
29
+ ### JSS API objects, like computers and mobile devices.
30
+ ###
31
+
32
+
33
+ #####################################
34
+ ### Module Variables
35
+ #####################################
36
+
37
+ #####################################
38
+ ### Module Methods
39
+ #####################################
40
+
41
+ #####################################
42
+ ### Sub-Modules
43
+ #####################################
44
+
45
+ ###
46
+ ### Simple match-based searches in the JSS.
47
+ ###
48
+ ### The API offers a simple match-based search for some objects, analagous to the
49
+ ### search field at the top of the Computers, MobileDevices, and Users sections of the
50
+ ### JSS WebApp.
51
+ ###
52
+ ### When a class extends itself with this module, it will acquire the .match Class Method
53
+ ### which performs a match and returns an Array of matching items.
54
+ ###
55
+ ### This module should be mixed in with #extend, not #include
56
+ ###
57
+ module Matchable
58
+
59
+ #####################################
60
+ ### Constants
61
+ #####################################
62
+
63
+ MATCHABLE = true
64
+
65
+ MATCH_RSRC = "match"
66
+
67
+ #####################################
68
+ ### Variables
69
+ #####################################
70
+
71
+ #####################################
72
+ ### Mixed-in Instance Methods
73
+ #####################################
74
+
75
+ #####################################
76
+ ### Extended Class Methods
77
+ #####################################
78
+
79
+ ###
80
+ ### Perform a match, returning an Array of Hashes, one for each item matched
81
+ ###
82
+ ### At the moment, it appears the search is an "exact match" search
83
+ ### regardless of the prefs of the user connected to the API.
84
+ ###
85
+ ### @param term[String] the term to match.
86
+ ###
87
+ ### @return [Array<Hash>] the item smatched.
88
+ ###
89
+ def match(term)
90
+ raise JSS::InvalidDataError, "Match term may not be empty" if term.to_s.empty?
91
+ rsrc = "#{self::RSRC_BASE}/#{JSS::Matchable::MATCH_RSRC}/#{term}"
92
+ JSS::API.get_rsrc(rsrc)[self::RSRC_LIST_KEY]
93
+ end
94
+
95
+ end # module Matchable
96
+
97
+ end # module
@@ -0,0 +1,556 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Variables
30
+ #####################################
31
+
32
+ #####################################
33
+ ### Module Methods
34
+ #####################################
35
+
36
+ #####################################
37
+ ### Classes
38
+ #####################################
39
+
40
+ ###
41
+ ### This class represents a Mobile Device stored in the JSS.
42
+ ###
43
+ ### ---
44
+ ### ===Adding devices to the JSS
45
+ ###
46
+ ### This class cannot be used to add new mobile devices to the JSS. That can only be done
47
+ ### via the enrollment process. See JSS::MobileDeviceInvitation for sending
48
+ ### an enrollment invite to a device.
49
+ ###
50
+ ### ---
51
+ ### ===Editing values
52
+ ###
53
+ ### Only a few values can be changed via the API, using these methods, q.v:
54
+ ### - #asset_tag= String
55
+ ### - #extension_attribute= Hash of :name or :id, and :value
56
+ ### - #location= Hash of values in @location, not all are required
57
+ ### - #purchasing= Hash of values in @purchasing, not all are required
58
+ ###
59
+ ### After modfying any values, #save must be called to save changes to the JSS.
60
+ ###
61
+ ### ---
62
+ ### ===MDM Commands
63
+ ###
64
+ ### The following methods can be used to send an APNS command to the device represented by an
65
+ ### instance of JSS::MobileDevice, equivalent to clicking one of the buttons on
66
+ ### the Management Commands section of the Management tab of the Mobile Device details page in the JSS UI.
67
+ ###
68
+ ### The methods supported are:
69
+ ### - blank_push (aliases blank, noop, send_blank_push)
70
+ ### - update_inventory (alias recon)
71
+ ### - device_lock (aliases lock, lock_device)
72
+ ### - erase_device (aliases wipe)
73
+ ### - clear_passcode
74
+ ### - unmanage_device (alias unmanage)
75
+ ###
76
+ ### Each returns true if the command as sent.
77
+ ###
78
+ ### @see JSS::APIObject
79
+ ###
80
+ ###
81
+ class MobileDevice < JSS::APIObject
82
+
83
+ #####################################
84
+ ### Mix-Ins
85
+ #####################################
86
+
87
+ include JSS::Updatable
88
+ include JSS::Locatable
89
+ include JSS::Purchasable
90
+ include JSS::Uploadable
91
+ include JSS::Extendable
92
+
93
+ extend JSS::Matchable
94
+
95
+ #####################################
96
+ ### Class Methods
97
+ #####################################
98
+
99
+ ### @return [Array<String>] all mobiledevice serial_numbers
100
+ def self.all_serial_numbers(refresh = false)
101
+ self.all(refresh).map{|i| i[:serial_number]}
102
+ end
103
+
104
+ ### @return [Array<String>] all mobiledevice phone numbers
105
+ def self.all_phone_numbers(refresh = false)
106
+ self.all(refresh).map{|i| i[:phone_number]}.select{|p| not p.empty?}
107
+ end
108
+
109
+ ### @return [Array<String>] all mobiledevice wifi mac addrs
110
+ def self.all_wifi_mac_addresses(refresh = false)
111
+ self.all(refresh).map{|i| i[:wifi_mac_address]}
112
+ end
113
+
114
+ ### @return [Array<String>] all mobiledevice udids
115
+ def self.all_udids(refresh = false)
116
+ self.all(refresh).map{|i| i[:udid]}
117
+ end
118
+
119
+ ### @return [Array<Hash>] the list of all managed mobile devices
120
+ def self.all_managed(refresh = false)
121
+ self.all(refresh).select{|d| d[:managed] }
122
+ end
123
+
124
+ ### @return [Array<Hash>] the list of all unmanaged mobile devices
125
+ def self.all_unmanaged(refresh = false)
126
+ self.all(refresh).select{|d| not d[:managed] }
127
+ end
128
+
129
+ ### @return [Array<Hash>] the list of all iPhones
130
+ def self.all_iphones(refresh = false)
131
+ self.all(refresh).select{|d| d[:model].start_with? "iPhone" }
132
+ end
133
+
134
+ ### @return [Array<Hash>] the list of all iPads
135
+ def self.all_ipads(refresh = false)
136
+ self.all(refresh).select{|d| d[:model].start_with? "iPad" }
137
+ end
138
+
139
+ ###
140
+ ### Send an MDM command to a managed mobile device.
141
+ ###
142
+ ### @param dev[Integer,String] the id, name, serialnum, udid, phone num, or wifi macaddr of the device
143
+ ###
144
+ ### @param command[Symbol] the command to send, one of the keys of MOBILE_DEV_MDM_COMMANDS
145
+ ###
146
+ ### @return [Boolean] true if command was sent successfully
147
+ ###
148
+ ### See also {#blank_push}, {#update_inventory}, {#device_lock},
149
+ ### {#erase_device}, {#clear_passcode}, and {#unmanage_device}
150
+ ###
151
+ def self.send_mdm_command(dev,command)
152
+
153
+ raise JSS::NoSuchItemError, "Unknown command '#{command}'" unless MOBILE_DEV_MDM_COMMANDS.keys.include? command
154
+ command_xml ="#{JSS::APIConnection::XML_HEADER}<mobile_device><command>#{MOBILE_DEV_MDM_COMMANDS[command]}</command></mobile_device>"
155
+ the_id = nil
156
+ self.all_managed.each do |mmd|
157
+ if [mmd[:id], mmd[:name], mmd[:serial_number], mmd[:phone_number], mmd[:udid], mmd[:wifi_mac_address]].include? dev
158
+ the_id = mmd[:id]
159
+ break
160
+ end
161
+ end # each do mmd
162
+
163
+ if the_id
164
+ response = JSS::API.put_rsrc( "#{RSRC_BASE}/id/#{the_id}", command_xml)
165
+ response =~ %r{<notification_sent>(.+)</notification_sent>}
166
+ return ($1 and $1 == "true")
167
+ end
168
+ raise JSS::UnmanagedError, "Cannot send command to unknown/unmanaged device '#{dev}'"
169
+ end
170
+
171
+ #####################################
172
+ ### Class Constants
173
+ #####################################
174
+ ### The base for REST resources of this class
175
+ RSRC_BASE = "mobiledevices"
176
+
177
+ ### the hash key used for the JSON list output of all objects in the JSS
178
+ RSRC_LIST_KEY = :mobile_devices
179
+
180
+ ### The hash key used for the JSON object output.
181
+ ### It's also used in various error messages
182
+ RSRC_OBJECT_KEY = :mobile_device
183
+
184
+ ### these keys, as well as :id and :name, are present in valid API JSON data for this class
185
+ VALID_DATA_KEYS = [:device_name, :capacity, :tethered ]
186
+
187
+ ### This class lets us seach for computers
188
+ SEARCH_CLASS = JSS::AdvancedMobileDeviceSearch
189
+
190
+ ### This is the class for relevant Extension Attributes
191
+ EXT_ATTRIB_CLASS = JSS::MobileDeviceExtensionAttribute
192
+
193
+ #######
194
+ ### The MDM commands sendable via the api
195
+ ### and alternative versions
196
+ ###
197
+ MOBILE_DEV_MDM_COMMANDS = {
198
+ :blank_push => "BlankPush",
199
+ :send_blank_push => "BlankPush",
200
+ :blank => "BlankPush",
201
+ :noop => "BlankPush",
202
+ :update_inventory => "UpdateInventory",
203
+ :recon => "UpdateInventory",
204
+ :device_lock => "DeviceLock",
205
+ :lock => "DeviceLock",
206
+ :lock_device => "DeviceLock",
207
+ :erase_device => "EraseDevice",
208
+ :erase => "EraseDevice",
209
+ :wipe => "EraseDevice",
210
+ :clear_passcode => "ClearPasscode",
211
+ :unmanage_device => "UnmanageDevice",
212
+ :unmanage => "UnmanageDevice"
213
+ }
214
+
215
+
216
+ #####################################
217
+ ### Attributes
218
+ #####################################
219
+
220
+ ############
221
+ ### The values returned in the General and Location subset are stored as direct attributes
222
+ ### Here are the Location values
223
+
224
+ ### @return [String] the airplay passwd on devices that can receive AirPlay (i.e. apple tvs)
225
+ attr_reader :airplay_password
226
+
227
+ ### @return [String] the asset tag
228
+ attr_reader :asset_tag
229
+
230
+ ### @return [Intger] how much space available on the device?
231
+ attr_reader :available_mb
232
+
233
+ ### @return [Integer] total storage on the device
234
+ attr_reader :capacity_mb
235
+
236
+ ### @return [Integer] how much of the capacity is in use?
237
+ attr_reader :percentage_used
238
+
239
+ ### @return [Integer] what percentage of the battery is remaining
240
+ attr_reader :battery_level
241
+
242
+ ### @return [String] the bluetooth mac addr
243
+ attr_reader :bluetooth_mac_address
244
+
245
+ ### @return [String] the wifi mac addr
246
+ attr_reader :wifi_mac_address
247
+
248
+ ### @return [Hash] !{:name=>"xxx", :id=>nnn} the computer associated with this device
249
+ attr_reader :computer
250
+
251
+ ### @return [String] what is this??
252
+ attr_reader :device_id
253
+
254
+ ### @return [String] the API's device_name and display_name are not used.
255
+ attr_reader :name
256
+
257
+ ### @return [Time] uses the value from the API's initial_entry_date_epoch
258
+ attr_reader :initial_entry_date
259
+
260
+ ### @return [String] the IP addr
261
+ attr_reader :ip_address
262
+
263
+ ### @return [String] the language setting
264
+ attr_reader :languages
265
+
266
+
267
+ ### @return [Time] uses the value from the API's last_backup_time_epoch
268
+ attr_reader :last_backup_time
269
+
270
+ ### @return [Time] uses the value from the API's last_inventory_update_utc
271
+ attr_reader :last_inventory_update
272
+
273
+ ### @return [String] the locales
274
+ attr_reader :locales
275
+
276
+ ### @return [Boolean] is this device managed?
277
+ attr_reader :managed
278
+
279
+ ### @return [String] the display name of the model
280
+ attr_reader :model_display
281
+
282
+ ### @return [String] the model identifier
283
+ attr_reader :model_identifier
284
+
285
+ ### @return [String] the model firmware
286
+ attr_reader :modem_firmware
287
+
288
+ ### @return [String] the OS version
289
+ attr_reader :os_version
290
+
291
+ ### @return [String] the OS build
292
+ attr_reader :os_build
293
+
294
+ ### @return [String] the phone number of the device's SIM card
295
+ attr_reader :phone_number
296
+
297
+ ### @return [String] the serial numbee
298
+ attr_reader :serial_number
299
+
300
+
301
+ ### @return [String] the site associated with this device
302
+ attr_reader :site
303
+
304
+ ### @return [Boolean] Is this device supervised?
305
+ attr_reader :supervised
306
+
307
+ ### @return [String] the tether state of the device
308
+ attr_reader :tethered
309
+
310
+ ### @return [String] the udid
311
+ attr_reader :udid
312
+
313
+ ### @return [Array<Hash>] the applications on the devices
314
+ attr_reader :applications
315
+
316
+ ### @return [Array<Hash>]
317
+ ###
318
+ ### The certificates on the device
319
+ ###
320
+ ### Each has has two keys:
321
+ ### - :identity => Boolean
322
+ ### - :common_name => String, possibly a udid
323
+ attr_reader :certificates
324
+
325
+ ### @return [Array<Hash>]
326
+ ###
327
+ ### One for each ConfigurationProfile on the device
328
+ ###
329
+ ### The Hash keys are:
330
+ ### - :identifier => a unique id, often the sams as the uuid
331
+ ### - :display_name => its name in the JSS
332
+ ### - :uuid => the ConfigurationProfile uuid
333
+ ### - :version => a String
334
+ attr_reader :configuration_profiles
335
+
336
+
337
+ ### @return [Array<Hash>]
338
+ ###
339
+ ### One for each group to which the device belongs
340
+ ###
341
+ ### The Hash keys are:
342
+ ### - :name => the group name
343
+ ### - :id => the group id in the JSS
344
+ attr_reader :mobile_device_groups
345
+
346
+ ### @return [Hash]
347
+ ###
348
+ ### A Hash of network data
349
+ ###
350
+ ### The Hash keys are:
351
+ ### - :voice_roaming_enabled=>"Disabled",
352
+ ### - :current_mobile_network_code=>"nnn",
353
+ ### - :imei=>"nn nnnnnn nnnnnn n",
354
+ ### - :home_mobile_country_code=>"nnn",
355
+ ### - :iccid=>"nnnn nnnn nnnn nnnn nnnn",
356
+ ### - :home_mobile_network_code=>"nnn",
357
+ ### - :current_carrier_network=>"",
358
+ ### - :data_roaming_enabled=>false,
359
+ ### - :home_carrier_network=>"AT&T",
360
+ ### - :carrier_settings_version=>"16.0",
361
+ ### - :roaming=>false,
362
+ ### - :cellular_technology=>"GSM",
363
+ ### - :current_mobile_country_code=>"nnn"
364
+ attr_reader :network
365
+
366
+ ### @return [Array<Hash>]
367
+ ###
368
+ ### One per provisioning profile
369
+ ###
370
+ attr_reader :provisioning_profiles
371
+
372
+ ### @return [Hash]
373
+ ###
374
+ ### A Hash of security data
375
+ ###
376
+ ### The Hash has these keys, all of which are Boolean
377
+ ### - :passcode_present=>true,
378
+ ### - :passcode_compliant=>true,
379
+ ### - :passcode_compliant_with_profile=>true,
380
+ ### - :data_protection=>true,
381
+ ### - :block_level_encryption_capable=>true,
382
+ ### - :file_level_encryption_capable=>true
383
+ attr_reader :security
384
+
385
+
386
+ #####################################
387
+ ### Instance Methods
388
+ #####################################
389
+
390
+ ###
391
+ ### @see APIObject#initialize
392
+ ###
393
+ def initialize(args = {})
394
+
395
+ super args, [:udid, :serialnumber, :macaddress]
396
+
397
+ gen = @init_data[:general]
398
+ @airplay_password = gen[:airplay_password]
399
+ @asset_tag = gen[:asset_tag]
400
+ @available_mb = gen[:available_mb]
401
+ @battery_level = gen[:battery_level]
402
+ @bluetooth_mac_address = gen[:bluetooth_mac_address]
403
+ @capacity_mb = gen[:capacity_mb]
404
+ @computer = gen[:computer]
405
+ @device_id = gen[:device_id]
406
+ @device_name = gen[:device_name]
407
+ @display_name = gen[:display_name]
408
+ @initial_entry_date = JSS.epoch_to_time gen[:initial_entry_date_epoch]
409
+ @ip_address = gen[:ip_address]
410
+ @languages = gen[:languages]
411
+ @last_backup_time = JSS.epoch_to_time gen[:last_backup_time_epoch]
412
+ @last_inventory_update = JSS.epoch_to_time gen[:last_inventory_update_epoch]
413
+ @locales = gen[:locales]
414
+ @managed = gen[:managed]
415
+ @model_display = gen[:model_display]
416
+ @model_identifier = gen[:model_identifier]
417
+ @modem_firmware = gen[:modem_firmware]
418
+ @os_build = gen[:os_build]
419
+ @os_version = gen[:os_version]
420
+ @percentage_used = gen[:percentage_used]
421
+ @phone_number = gen[:phone_number]
422
+ @serial_number = gen[:serial_number]
423
+ @site = JSS::APIObject.get_name(gen[:site])
424
+ @supervised = gen[:supervised]
425
+ @tethered = gen[:tethered]
426
+ @udid = gen[:udid]
427
+ @wifi_mac_address = gen[:wifi_mac_address]
428
+
429
+ parse_location
430
+ parse_purchasing
431
+ parse_ext_attrs
432
+
433
+ @mobile_device_groups = @init_data[:mobile_device_groups]
434
+ @network = @init_data[:network]
435
+ @extension_attributes = @init_data[:extension_attributes]
436
+ @certificates = @init_data[:certificates]
437
+ @configuration_profiles = @init_data[:configuration_profiles]
438
+ @provisioning_profiles = @init_data[:provisioning_profiles]
439
+ @security = @init_data[:security]
440
+
441
+ end # initialize
442
+
443
+ ###
444
+ ### Send a blank_push MDM command
445
+ ###
446
+ ### @see MobileDevice.send_mdm_command
447
+ ###
448
+ ### @return [Boolean]
449
+ ###
450
+ def blank_push
451
+ self.class.send_mdm_command @id, :blank_push
452
+ end
453
+
454
+
455
+
456
+ ###
457
+ ### Send an update_inventory MDM command
458
+ ###
459
+ ### @see MobileDevice.send_mdm_command
460
+ ###
461
+ ### @return [Boolean]
462
+ ###
463
+ def update_inventory
464
+ self.class.send_mdm_command @id, :update_inventory
465
+ end
466
+
467
+ ###
468
+ ### Send a device_lock MDM command
469
+ ###
470
+ ### @see MobileDevice.send_mdm_command
471
+ ###
472
+ ### @return [Boolean]
473
+ ###
474
+ def device_lock
475
+ self.class.send_mdm_command @id, :device_lock
476
+ end
477
+
478
+
479
+ ###
480
+ ### Send an erase_device MDM command
481
+ ###
482
+ ### @see MobileDevice.send_mdm_command
483
+ ###
484
+ ### @return [Boolean]
485
+ ###
486
+ def erase_device
487
+ self.class.send_mdm_command @id, :erase_device
488
+ end
489
+
490
+
491
+ ###
492
+ ### Send a clear_passcode MDM command
493
+ ###
494
+ ### @see MobileDevice.send_mdm_command
495
+ ###
496
+ ### @return [Boolean]
497
+ ###
498
+ def clear_passcode
499
+ self.class.send_mdm_command @id, :clear_passcode
500
+ end
501
+
502
+ ###
503
+ ### Send a unmanage_device MDM command
504
+ ###
505
+ ### @see MobileDevice.send_mdm_command
506
+ ###
507
+ ### @return [Boolean]
508
+ ###
509
+ def unmanage_device
510
+ @managed = false if self.class.send_mdm_command(@id, :unmanage_device)
511
+ end
512
+
513
+
514
+ ### Aliases
515
+ alias battery_percent battery_level
516
+ alias managed? managed
517
+ alias sn serial_number
518
+ alias serialnumber serial_number
519
+
520
+ alias noop blank_push
521
+ alias send_blank_push blank_push
522
+ alias recon update_inventory
523
+ alias lock device_lock
524
+ alias lock_device device_lock
525
+ alias erase erase_device
526
+ alias wipe erase_device
527
+ alias unmanage unmanage_device
528
+ alias make_unmanaged unmanage_device
529
+
530
+
531
+
532
+
533
+ ##############################
534
+ # private methods
535
+ ##############################
536
+
537
+ private
538
+
539
+ def rest_xml
540
+ doc = REXML::Document.new APIConnection::XML_HEADER
541
+ md = doc.add_element self.class::RSRC_OBJECT_KEY.to_s
542
+
543
+ md << ext_attr_xml
544
+
545
+ if has_location?
546
+ md << location_xml
547
+ end
548
+ if has_purchasing?
549
+ md << purchasing_xml
550
+ end
551
+
552
+ return doc.to_s
553
+ end
554
+
555
+ end # class Mobile Device
556
+ end # module