ruby-jss 1.4.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +95 -0
  3. data/THANKS.md +3 -2
  4. data/lib/jamf.rb +18 -17
  5. data/lib/jamf/api/base_classes/collection_resource.rb +613 -0
  6. data/lib/jamf/api/{abstract_classes → base_classes}/json_object.rb +109 -101
  7. data/lib/jamf/api/{abstract_classes → base_classes}/prestage.rb +55 -30
  8. data/lib/jamf/api/{abstract_classes → base_classes}/resource.rb +10 -6
  9. data/lib/jamf/api/{abstract_classes → base_classes}/singleton_resource.rb +4 -3
  10. data/lib/jamf/api/connection.rb +13 -9
  11. data/lib/jamf/api/connection/api_error.rb +8 -8
  12. data/lib/jamf/api/connection/token.rb +16 -15
  13. data/lib/jamf/api/json_objects/device_enrollment_device.rb +14 -7
  14. data/lib/jamf/api/json_objects/{location.rb → device_enrollment_device_sync_state.rb} +27 -41
  15. data/lib/jamf/api/json_objects/device_enrollment_sync_status.rb +1 -1
  16. data/lib/jamf/api/json_objects/{attachment.rb → locale.rb} +14 -23
  17. data/lib/jamf/api/json_objects/md_prestage_name.rb +1 -1
  18. data/lib/jamf/api/json_objects/md_prestage_names.rb +2 -2
  19. data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +50 -1
  20. data/lib/jamf/api/json_objects/prestage_assignment.rb +2 -2
  21. data/lib/jamf/api/json_objects/prestage_location.rb +3 -3
  22. data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +7 -7
  23. data/lib/jamf/api/json_objects/prestage_scope.rb +1 -1
  24. data/lib/jamf/api/{resources/collection_resources → json_objects}/time_zone.rb +9 -23
  25. data/lib/jamf/api/mixins/{abstract.rb → base_class.rb} +34 -16
  26. data/lib/jamf/api/mixins/bulk_deletable.rb +27 -6
  27. data/lib/jamf/api/mixins/change_log.rb +201 -51
  28. data/lib/jamf/api/{resources/collection_resources/computer.rb → mixins/filterable.rb} +19 -17
  29. data/lib/jamf/api/mixins/pageable.rb +208 -0
  30. data/lib/jamf/api/{json_objects/installed_application.rb → mixins/sortable.rb} +33 -33
  31. data/lib/jamf/api/resources/collection_resources/building.rb +16 -9
  32. data/lib/jamf/api/resources/collection_resources/category.rb +5 -4
  33. data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +12 -5
  34. data/lib/jamf/api/resources/collection_resources/department.rb +0 -2
  35. data/lib/jamf/api/resources/collection_resources/device_enrollment.rb +10 -10
  36. data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +11 -3
  37. data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +25 -23
  38. data/lib/jamf/api/resources/collection_resources/script.rb +61 -25
  39. data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +15 -5
  40. data/lib/jamf/api/resources/singleton_resources/locales.rb +155 -0
  41. data/lib/jamf/api/resources/singleton_resources/time_zones.rb +213 -0
  42. data/lib/jamf/client.rb +3 -3
  43. data/lib/jamf/client/management_action.rb +2 -3
  44. data/lib/jamf/composer.rb +2 -2
  45. data/lib/jamf/utility.rb +35 -7
  46. data/lib/jamf/validate.rb +63 -24
  47. data/lib/jamf/version.rb +1 -1
  48. data/lib/jss.rb +2 -2
  49. data/lib/jss/api_connection.rb +114 -406
  50. data/lib/jss/api_object.rb +3 -19
  51. data/lib/jss/api_object/categorizable.rb +1 -1
  52. data/lib/jss/api_object/computer.rb +13 -0
  53. data/lib/jss/api_object/configuration_profile.rb +61 -5
  54. data/lib/jss/api_object/directory_binding_type.rb +66 -60
  55. data/lib/jss/api_object/directory_binding_type/active_directory.rb +71 -34
  56. data/lib/jss/api_object/directory_binding_type/admitmac.rb +536 -467
  57. data/lib/jss/api_object/directory_binding_type/centrify.rb +21 -7
  58. data/lib/jss/api_object/directory_binding_type/open_directory.rb +4 -4
  59. data/lib/jss/api_object/distribution_point.rb +2 -2
  60. data/lib/jss/api_object/dock_item.rb +102 -96
  61. data/lib/jss/api_object/extendable.rb +1 -1
  62. data/lib/jss/api_object/group.rb +33 -2
  63. data/lib/jss/api_object/network_segment.rb +45 -13
  64. data/lib/jss/api_object/patch_source.rb +10 -9
  65. data/lib/jss/api_object/policy.rb +155 -25
  66. data/lib/jss/api_object/printer.rb +10 -4
  67. data/lib/jss/api_object/scopable.rb +10 -15
  68. data/lib/jss/api_object/scopable/scope.rb +31 -30
  69. data/lib/jss/api_object/script.rb +242 -352
  70. data/lib/jss/api_object/user.rb +1 -1
  71. data/lib/jss/client/management_action.rb +1 -2
  72. data/lib/jss/composer.rb +2 -2
  73. data/lib/jss/exceptions.rb +3 -0
  74. data/lib/jss/server.rb +15 -0
  75. data/lib/jss/utility.rb +213 -45
  76. data/lib/jss/version.rb +1 -1
  77. metadata +46 -64
  78. data/lib/jamf/api/abstract_classes/advanced_search.rb +0 -86
  79. data/lib/jamf/api/abstract_classes/collection_resource.rb +0 -433
  80. data/lib/jamf/api/abstract_classes/generic_reference.rb +0 -145
  81. data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +0 -126
  82. data/lib/jamf/api/json_objects/account_prefs.rb +0 -79
  83. data/lib/jamf/api/json_objects/android_details.rb +0 -139
  84. data/lib/jamf/api/json_objects/appletv_details.rb +0 -110
  85. data/lib/jamf/api/json_objects/cellular_network.rb +0 -151
  86. data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +0 -67
  87. data/lib/jamf/api/json_objects/criterion.rb +0 -152
  88. data/lib/jamf/api/json_objects/extension_attribute_value.rb +0 -128
  89. data/lib/jamf/api/json_objects/installed_certificate.rb +0 -53
  90. data/lib/jamf/api/json_objects/installed_configuration_profile.rb +0 -67
  91. data/lib/jamf/api/json_objects/installed_ebook.rb +0 -58
  92. data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +0 -59
  93. data/lib/jamf/api/json_objects/ios_details.rb +0 -244
  94. data/lib/jamf/api/json_objects/mobile_device_details.rb +0 -219
  95. data/lib/jamf/api/json_objects/mobile_device_security.rb +0 -101
  96. data/lib/jamf/api/json_objects/purchasing_data.rb +0 -125
  97. data/lib/jamf/api/mixins/locatable.rb +0 -124
  98. data/lib/jamf/api/mixins/referable.rb +0 -92
  99. data/lib/jamf/api/resources/collection_resources/account.rb +0 -163
  100. data/lib/jamf/api/resources/collection_resources/advanced_mobile_device_search.rb +0 -52
  101. data/lib/jamf/api/resources/collection_resources/advanced_user_search.rb +0 -52
  102. data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +0 -45
  103. data/lib/jamf/api/resources/collection_resources/mobile_device.rb +0 -315
  104. data/lib/jamf/api/resources/collection_resources/site.rb +0 -77
  105. data/lib/jamf/api/resources/singleton_resources/authorization.rb +0 -88
  106. data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +0 -139
  107. data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +0 -95
@@ -168,7 +168,7 @@ module JSS
168
168
  @phone_number = @init_data[:phone_number]
169
169
  @position = @init_data[:position]
170
170
  @ldap_server = JSS::APIObject.get_name @init_data[:ldap_server]
171
- @ldap_server_id = @init_data[:ldap_server][:id]
171
+ @ldap_server_id = @init_data[:ldap_server][:id] unless @init_data[:ldap_server].nil?
172
172
  @sites = @init_data[:sites] ? @init_data[:sites] : []
173
173
 
174
174
  if @init_data[:links]
@@ -103,8 +103,7 @@ module JSS
103
103
  orig_flags = flags
104
104
  prefs['apps'] << { 'bundle-id' => MGMT_ACTION_BUNDLE_ID, 'flags' => flags }
105
105
  end
106
- # system "/usr/bin/defaults write #{NCPREFS_DOMAIN} '#{prefs.to_plist}'"
107
- plist.open('w') { |f| f.write prefs.to_plist }
106
+ plist.open('w') { |f| f.write JSS.xml_plist_from(prefs) }
108
107
  system HUP_NOTIF_CTR_CMD if hup
109
108
  orig_flags
110
109
  end
data/lib/jss/composer.rb CHANGED
@@ -126,7 +126,7 @@ module JSS
126
126
  ###
127
127
  comp_plist_out = Pathname.new "/tmp/#{PKG_BUNDLE_ID_PFX}-#{pkg_filename}.plist"
128
128
  system "#{PKGBUILD} --analyze --root '#{root}' '#{comp_plist_out}'"
129
- comp_plist = Plist.parse_xml comp_plist_out.read
129
+ comp_plist = JSS.parse_plist comp_plist_out
130
130
 
131
131
  ### if the plist is empty, there are no bundles in the pkg
132
132
  if comp_plist[0].nil?
@@ -141,7 +141,7 @@ module JSS
141
141
  bndl['BundleHasStrictIdentifier'] = false
142
142
  end
143
143
  ### write out the edits
144
- comp_plist_out.open('w') { |f| f.write comp_plist.to_plist }
144
+ comp_plist_out.open('w') { |f| f.write JSS.xml_plist_from(comp_plist) }
145
145
  comp_plist_arg = "--component-plist '#{comp_plist_out}'"
146
146
  end
147
147
 
@@ -87,6 +87,9 @@ module JSS
87
87
  ###
88
88
  class AuthenticationError < RuntimeError; end
89
89
 
90
+ ###
91
+ class AuthorizationError < RuntimeError ; end
92
+
90
93
  ### ConflictError - raise this when
91
94
  ### attempts to PUT or PUSH to the API
92
95
  ### result in a 409 Conflict http error.
data/lib/jss/server.rb CHANGED
@@ -110,6 +110,21 @@ module JSS
110
110
  @act_code_data[:code]
111
111
  end
112
112
 
113
+ # Update the activation code and organization name for this server
114
+ #
115
+ # @param org: [String] the organization to which the server is licensed
116
+ # @param code: [String ] the activation code for the server licence
117
+ #
118
+ # @return [void]
119
+ def update_activation_code(org:, code:)
120
+ xml = REXML::Document.new JSS::APIConnection::XML_HEADER
121
+ acode = xml.add_element ACTIVATION_CODE_KEY.to_s
122
+ acode.add_element('organization_name').text = org
123
+ acode.add_element('code').text = code
124
+
125
+ @api.put_rsrc ACTIVATION_CODE_RSRC, xml.to_s
126
+ end
127
+
113
128
  # Remove the api object from
114
129
  # the instance_variables used to create
115
130
  # pretty-print (pp) output.
data/lib/jss/utility.rb CHANGED
@@ -23,61 +23,195 @@
23
23
  #
24
24
  #
25
25
 
26
- #
27
26
  module JSS
28
27
 
29
28
  # A collection of useful utility methods. Mostly for
30
29
  # converting values between formats, parsing data, and
31
30
  # user interaction.
32
31
 
33
- # Converts an OS Version into an Array of higher OS versions.
32
+ # Hash of 'minor' => 'maint'
33
+ # The maximum maint release for macOS 10.minor.maint
34
+ # e.g the highest release of 10.6 was 10.6.8, the highest release of
35
+ # 10.15 was 10.15.7
36
+ #
37
+ # 12 is the default for the current OS and higher
38
+ # (and hoping apple doesn't release 10.16.13)
39
+ OS_TEN_MAXS = {
40
+ 2 => 8,
41
+ 3 => 9,
42
+ 4 => 11,
43
+ 5 => 8,
44
+ 6 => 8,
45
+ 7 => 5,
46
+ 8 => 5,
47
+ 9 => 5,
48
+ 10 => 5,
49
+ 11 => 6,
50
+ 12 => 6,
51
+ 13 => 6,
52
+ 14 => 6,
53
+ 15 => 7
54
+ }
55
+
56
+ # Hash of 'major' => 'minor'
57
+ # The maximum minor release for macOS major.minor
58
+ # e.g. the highest release of 11 is 11.12
59
+ #
60
+ # 12 is the default for the current OS and higher
61
+ # (and hoping apple doesn't release, e.g., 11.13)
62
+ MAC_OS_MAXS = {
63
+ 11 => 12,
64
+ 12 => 12,
65
+ 13 => 12,
66
+ 14 => 12,
67
+ 15 => 12,
68
+ 16 => 12,
69
+ 17 => 12,
70
+ 18 => 12,
71
+ 19 => 12,
72
+ 20 => 12
73
+ }
74
+
75
+ # Converts an OS Version into an Array of equal or higher OS versions, up to
76
+ # some non-existant max, hopefully far in the future, currently 20.12.10
77
+ #
78
+ # This array can then be joined with commas and used as the value of the
79
+ # os_requirements for Packages and Scripts.
34
80
  #
35
- # It's unlikely that this library will still be in use as-is by the release of OS X 10.30.
36
- # Hopefully well before then JAMF will implement a "minimum OS" in the JSS itself.
81
+ # It's unlikely that this method, as written, will still be in use by
82
+ # the release of macOS 20.12.10, but currently thats the upper limit.
37
83
  #
38
- # @param min_os [String] the mimimum OS version to expand, e.g. ">=10.6.7" or "10.6.7"
84
+ # Hopefully well before then JAMF will implement a "minimum OS" in Jamf Pro
85
+ # itself, then we could avoid the inherant limitations in using a method like
86
+ # this.
39
87
  #
40
- # @return [Array] Nearly all potential OS versions from the minimum to 10.19.x.
88
+ # When the highest maint. release of an OS version is not known, because its
89
+ # the currently released OS version or higher, then this method assumes '12'
90
+ # e.g. '10.16.12', '11.12', '12.12', etc.
91
+ #
92
+ # Apple has never released more than 11 updates to a version of macOS
93
+ # (that being 10.4), so hopefully 12 is enough
94
+ #
95
+ # Since Big Sur might report itself as either '10.16' or '11.x.x', this method
96
+ # will allow for both possibilities, and the array will contain whatever
97
+ # iterations needed for both version numbers
98
+ #
99
+ # @param min_os [String] the mimimum OS version to expand, e.g. ">=10.9.4" or "11.1"
100
+ #
101
+ # @return [Array] Nearly all potential OS versions from the minimum to 20.12.10
41
102
  #
42
103
  # @example
43
- # JSS.expand_min_os ">=10.6.7" # => returns this array
44
- # # ["10.6.7",
45
- # # "10.6.8",
104
+ # JSS.expand_min_os ">=10.9.4" # => returns this array
105
+ # # ["10.9.4",
106
+ # # "10.9.5",
107
+ # # "10.10.x"
46
108
  # # ...
47
- # # "10.6.25",
48
- # # "10.7.x",
49
- # # "10.8.x",
109
+ # # "10.16.x",
110
+ # # "11.x",
111
+ # # "12.x",
50
112
  # # ...
51
- # # "10.30.x"]
113
+ # # "20.x"]
52
114
  #
53
115
  #
54
116
  def self.expand_min_os(min_os)
55
117
  min_os = min_os.delete '>='
56
118
 
57
119
  # split the version into major, minor and maintenance release numbers
58
- (maj, min, maint) = min_os.split('.')
120
+ major, minor, maint = min_os.split('.')
121
+ minor = 'x' if minor.nil? || minor == '0'
59
122
  maint = 'x' if maint.nil? || maint == '0'
60
123
 
61
- # if the maint release number is an "x" just start the list of OK OS's with it
62
- if maint == 'x'
63
- ok_oses = [maj + '.' + min.to_s + '.x']
124
+ ok_oses = []
64
125
 
65
- # otherwise, start with it and explicitly add all maint releases up to 15
66
- # (and hope apple doesn't do more than 15 maint releases for an OS)
67
- else
68
- ok_oses = []
69
- (maint.to_i..25).each do |m|
70
- ok_oses << maj + '.' + min + '.' + m.to_s
126
+ # Deal with 10.x.x up to 10.16
127
+ if major == '10'
128
+
129
+ # In big sur with SYSTEM_VERSION_COMPAT
130
+ # set, it will only ever report as `10.16`
131
+ # So if major is 10 and minor is 16, ignore maint
132
+ # and start explicitly at '10.16'
133
+ if minor == '16'
134
+ ok_oses << '10.16'
135
+
136
+ # But for Catalina and below, we need to
137
+ # expand things out
138
+ else
139
+ # e.g. 10.14.x
140
+ # doesn't expand to anything
141
+ if maint == 'x'
142
+ ok_oses << "10.#{minor}.x"
143
+
144
+ # e.g. 10.15.5
145
+ # expand to 10.15.5, 10.15.6, 10.15.7
146
+ else
147
+ max_maint_for_minor = OS_TEN_MAXS[minor.to_i]
148
+
149
+ (maint.to_i..max_maint_for_minor).each do |m|
150
+ ok_oses << "#{major}.#{minor}.#{m}"
151
+ end # each m
152
+ end # if maint == x
153
+
154
+ # now if we started below catalina, account for everything
155
+ # up to 10.15.x
156
+ if minor.to_i < 15
157
+ ((minor.to_i + 1)..15).each { |v| ok_oses << "10.#{v}.x" }
158
+ end
159
+
160
+ # and add big sur with SYSTEM_VERSION_COMPAT
161
+ ok_oses << '10.16'
162
+ end # if minor == 16
163
+
164
+ # now reset these so we can go higher
165
+ major = '11'
166
+ minor = 'x'
167
+ maint = 'x'
168
+ end # if major == 10
169
+
170
+ # if the min os is 11.0.0 or equiv, and we aven't added 10.16
171
+ # for SYSTEM_VERSION_COMPAT, add it now
172
+ if ['11', '11.x', '11.x.x', '11.0', '11.0.0'].include?(min_os) && !ok_oses.include?('10.16')
173
+ ok_oses << '10.16'
174
+ end
175
+
176
+ # e.g. 11.x, or 11.x.x
177
+ # expand to 11.x, 12.x, 13.x, ... 20.x
178
+ if minor == 'x'
179
+ ((major.to_i)..20).each { |v| ok_oses << "#{v}.x" }
180
+
181
+ # e.g. 11.2.x
182
+ # expand to 11.2.x, 11.3.x, ... 11.12.x,
183
+ # 12.x, 13.x, ... 20.x
184
+ elsif maint == 'x'
185
+ # first expand the minors out to their max
186
+ # e.g. 11.2.x, 11.3.x, ... 11.12.x
187
+ max_minor_for_major = MAC_OS_MAXS[major.to_i]
188
+ ((minor.to_i)..max_minor_for_major).each do |m|
189
+ ok_oses << "#{major}.#{m}.x"
71
190
  end # each m
191
+
192
+ # then add the majors out to 20
193
+ ((major.to_i + 1)..20).each { |v| ok_oses << "#{v}.x" }
194
+
195
+ # e.g. 11.2.3
196
+ # expand to 11.2.3, 11.2.4, ... 11.2.10,
197
+ # 11.3.x, 11.4.x, ... 11.12.x,
198
+ # 12.x, 13.x, ... 20.x
199
+ else
200
+ # first expand the maints out to 10
201
+ # e.g. 11.2.3, 11.2.4, ... 11.2.10
202
+ ((maint.to_i)..10).each { |mnt| ok_oses << "#{major}.#{minor}.#{mnt}" }
203
+
204
+ # then expand the minors out to their max
205
+ # e.g. 11.3.x, ... 11.12.x
206
+ max_minor_for_major = MAC_OS_MAXS[major.to_i]
207
+ ((minor.to_i + 1)..max_minor_for_major).each { |min| ok_oses << "#{major}.#{min}.x" }
208
+
209
+ # then add the majors out to 20
210
+ ((major.to_i + 1)..20).each { |v| ok_oses << "#{v}.x" }
72
211
  end
73
212
 
74
- # now account for all OS X versions starting with 10.
75
- # up to 10.30.x
76
- ((min.to_i + 1)..30).each do |v|
77
- ok_oses << maj + '.' + v.to_s + '.x'
78
- end # each v
79
213
  ok_oses
80
- end
214
+ end # def self.expand_min_os(min_os)
81
215
 
82
216
  # Scripts and packages can have processor limitations.
83
217
  # This method tests a given processor, against a requirement
@@ -95,6 +229,7 @@ module JSS
95
229
  #
96
230
  def self.processor_ok?(requirement, processor = nil)
97
231
  return true if requirement.to_s.empty? || requirement =~ /none/i
232
+
98
233
  processor ||= `/usr/bin/uname -p`
99
234
  requirement == (processor.to_s.include?('86') ? 'x86' : 'ppc')
100
235
  end
@@ -115,6 +250,7 @@ module JSS
115
250
  def self.os_ok?(requirement, os_to_check = nil)
116
251
  return true if requirement.to_s =~ /none/i
117
252
  return true if requirement.to_s == 'n'
253
+
118
254
  requirement = JSS.to_s_and_a(requirement)[:arrayform]
119
255
  return true if requirement.empty?
120
256
 
@@ -174,19 +310,26 @@ module JSS
174
310
  { stringform: valstr, arrayform: valarr }
175
311
  end # to_s_and_a
176
312
 
177
- # Parse a plist into a Ruby data structure.
178
- # This enhances Plist::parse_xml taking file paths, as well as XML Strings
179
- # and reading the files regardless of binary/XML format.
313
+ # Parse a plist into a Ruby data structure. The plist parameter may be
314
+ # a String containing an XML plist, or a path to a plist file, or it may be
315
+ # a Pathname object pointing to a plist file. The plist files may be XML or
316
+ # binary.
180
317
  #
181
318
  # @param plist[Pathname, String] the plist XML, or the path to a plist file
182
319
  #
320
+ # @param symbol_keys[Boolean] should any Hash keys in the result be converted
321
+ # into Symbols rather than remain as Strings?
322
+ #
183
323
  # @return [Object] the parsed plist as a ruby hash,array, etc.
184
324
  #
185
- def self.parse_plist(plist)
325
+ def self.parse_plist(plist, symbol_keys: false)
326
+ require 'cfpropertylist'
327
+
186
328
  # did we get a string of xml, or a string pathname?
187
329
  case plist
188
330
  when String
189
- return Plist.parse_xml plist if plist.include? '</plist>'
331
+ return CFPropertyList.native_types(CFPropertyList::List.new(data: plist).value, symbol_keys) if plist.include? '</plist>'
332
+
190
333
  plist = Pathname.new plist
191
334
  when Pathname
192
335
  true
@@ -197,9 +340,30 @@ module JSS
197
340
  # if we're here, its a Pathname
198
341
  raise JSS::MissingDataError, "No such file: #{plist}" unless plist.file?
199
342
 
200
- Plist.parse_xml `/usr/libexec/PlistBuddy -x -c print #{Shellwords.escape(plist.to_s)}`.force_encoding('UTF-8')
343
+ CFPropertyList.native_types(CFPropertyList::List.new(file: plist).value, symbol_keys)
201
344
  end # parse_plist
202
345
 
346
+ # Convert any ruby data to an XML plist.
347
+ #
348
+ # NOTE: Binary data is tricky. Easiest way is to pass in a
349
+ # Pathname or IO object (anything that responds to `read` and
350
+ # returns a bytestring)
351
+ # and then the CFPropertyList.guess method will read it and
352
+ # convert it to a Plist <data> element with base64 encoded
353
+ # data.
354
+ # For more info, see CFPropertyList.guess
355
+ #
356
+ # @param data [Object] the data to be converted, usually a Hash
357
+ #
358
+ # @return [String] the object converted into an XML plist
359
+ #
360
+ def self.xml_plist_from(data)
361
+ require 'cfpropertylist'
362
+ plist = CFPropertyList::List.new
363
+ plist.value = CFPropertyList.guess(data, convert_unknown_to_string: true)
364
+ plist.to_str(CFPropertyList::List::FORMAT_XML)
365
+ end
366
+
203
367
  # Converts anything that responds to #to_s to a Time, or nil
204
368
  #
205
369
  # Return nil if the item is nil, 0 or an empty String.
@@ -223,9 +387,7 @@ module JSS
223
387
 
224
388
  # if the UTC offset of the datetime is zero, make a new one with the correct local offset
225
389
  # (which might also be zero if we happen to be in GMT)
226
- if the_dt.offset.zero?
227
- the_dt = DateTime.new(the_dt.year, the_dt.month, the_dt.day, the_dt.hour, the_dt.min, the_dt.sec, JSS::TIME_ZONE_OFFSET)
228
- end
390
+ the_dt = DateTime.new(the_dt.year, the_dt.month, the_dt.day, the_dt.hour, the_dt.min, the_dt.sec, JSS::TIME_ZONE_OFFSET) if the_dt.offset.zero?
229
391
  # now convert it to a Time and return it
230
392
  Time.at the_dt.strftime('%s').to_i, usec
231
393
  end # parse_time
@@ -247,6 +409,7 @@ module JSS
247
409
  #
248
410
  def self.epoch_to_time(epoch)
249
411
  return nil if NIL_DATES.include? epoch
412
+
250
413
  Time.at(epoch.to_i / 1000.0)
251
414
  end # parse_date
252
415
 
@@ -266,6 +429,7 @@ module JSS
266
429
  def self.api_object_class(name)
267
430
  klass = api_object_names[name.downcase.to_sym]
268
431
  raise JSS::InvalidDataError, "Unknown API Object Class: #{name}" unless klass
432
+
269
433
  klass
270
434
  end
271
435
 
@@ -283,11 +447,13 @@ module JSS
283
447
  #
284
448
  def self.api_object_names
285
449
  return @api_object_names if @api_object_names
450
+
286
451
  @api_object_names ||= {}
287
452
  JSS.constants.each do |const|
288
453
  klass = JSS.const_get const
289
454
  next unless klass.is_a? Class
290
455
  next unless klass.ancestors.include? JSS::APIObject
456
+
291
457
  @api_object_names[klass.const_get(:RSRC_LIST_KEY).to_sym] = klass if klass.constants.include? :RSRC_LIST_KEY
292
458
  @api_object_names[klass.const_get(:RSRC_OBJECT_KEY).to_sym] = klass if klass.constants.include? :RSRC_OBJECT_KEY
293
459
  end
@@ -324,6 +490,7 @@ module JSS
324
490
  #
325
491
  def self.array_to_rexml_array(element, list)
326
492
  raise JSS::InvalidDataError, 'Arg. must be an Array.' unless list.is_a? Array
493
+
327
494
  element = element.to_s
328
495
  list.map do |v|
329
496
  e = REXML::Element.new(element)
@@ -350,6 +517,7 @@ module JSS
350
517
  #
351
518
  def self.hash_to_rexml_array(hash)
352
519
  raise InvalidDataError, 'Arg. must be a Hash.' unless hash.is_a? Hash
520
+
353
521
  ary = []
354
522
  hash.each_pair do |k, v|
355
523
  el = REXML::Element.new k.to_s
@@ -428,11 +596,11 @@ module JSS
428
596
 
429
597
  {
430
598
  major: major.to_i,
431
- minor: minor.to_i,
432
- revision: revision.to_i,
433
- maint: revision.to_i,
434
- patch: revision.to_i,
435
- build: build,
599
+ minor: minor.to_i,
600
+ revision: revision.to_i,
601
+ maint: revision.to_i,
602
+ patch: revision.to_i,
603
+ build: build,
436
604
  version: Gem::Version.new("#{major}.#{minor}.#{revision}")
437
605
  }
438
606
  end
@@ -457,6 +625,7 @@ module JSS
457
625
  @stdin_lines ||= ($stdin.tty? ? [] : $stdin.read.lines.map { |l| l.chomp("\n") })
458
626
 
459
627
  return @stdin_lines.join("\n") if line <= 0
628
+
460
629
  idx = line - 1
461
630
  @stdin_lines[idx]
462
631
  end
@@ -489,10 +658,9 @@ module JSS
489
658
  # @return [Boolean] The new state of devmode
490
659
  #
491
660
  def self.devmode(setting)
492
- @devmode = setting == :on ? true : false
661
+ @devmode = setting == :on
493
662
  end
494
663
 
495
-
496
664
  # is devmode currently on?
497
665
  #
498
666
  # @return [Boolean]