ruby-jss 1.0.3b2 → 1.0.3b3

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.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +5 -1
  3. data/README.md +31 -18
  4. data/bin/cgrouper +1 -1
  5. data/bin/jamfHelperBackgrounder +1 -1
  6. data/bin/netseg-update +1 -1
  7. data/data/ruby-jss.conf.example +24 -0
  8. data/lib/jss-api.rb +24 -0
  9. data/lib/jss.rb +1 -2
  10. data/lib/jss/api_connection.rb +7 -9
  11. data/lib/jss/api_object.rb +1 -1
  12. data/lib/jss/api_object/account.rb +1 -1
  13. data/lib/jss/api_object/advanced_search.rb +1 -1
  14. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +1 -1
  15. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +1 -1
  16. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +1 -1
  17. data/lib/jss/api_object/building.rb +1 -1
  18. data/lib/jss/api_object/categorizable.rb +1 -1
  19. data/lib/jss/api_object/category.rb +1 -1
  20. data/lib/jss/api_object/computer.rb +1 -1
  21. data/lib/jss/api_object/computer/application_installs.rb +1 -1
  22. data/lib/jss/api_object/computer_invitation.rb +1 -1
  23. data/lib/jss/api_object/configuration_profile.rb +1 -1
  24. data/lib/jss/api_object/configuration_profile/mobile_device_configuration_profile.rb +24 -0
  25. data/lib/jss/api_object/configuration_profile/osx_configuration_profile.rb +1 -1
  26. data/lib/jss/api_object/creatable.rb +1 -1
  27. data/lib/jss/api_object/criteriable.rb +1 -1
  28. data/lib/jss/api_object/criteriable/criteria.rb +1 -1
  29. data/lib/jss/api_object/criteriable/criterion.rb +1 -1
  30. data/lib/jss/api_object/department.rb +1 -1
  31. data/lib/jss/api_object/distribution_point.rb +1 -1
  32. data/lib/jss/api_object/ebook.rb +1 -1
  33. data/lib/jss/api_object/extendable.rb +1 -1
  34. data/lib/jss/api_object/extension_attribute.rb +1 -1
  35. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +1 -1
  36. data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +1 -1
  37. data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +1 -1
  38. data/lib/jss/api_object/group.rb +1 -1
  39. data/lib/jss/api_object/group/computer_group.rb +1 -1
  40. data/lib/jss/api_object/group/mobile_device_group.rb +1 -1
  41. data/lib/jss/api_object/group/user_group.rb +1 -1
  42. data/lib/jss/api_object/ldap_server.rb +1 -1
  43. data/lib/jss/api_object/locatable.rb +1 -1
  44. data/lib/jss/api_object/mac_application.rb +24 -0
  45. data/lib/jss/api_object/management_history.rb +1 -1
  46. data/lib/jss/api_object/management_history/audit_event.rb +24 -0
  47. data/lib/jss/api_object/management_history/casper_imaging_log.rb +24 -0
  48. data/lib/jss/api_object/management_history/casper_remote_log.rb +24 -0
  49. data/lib/jss/api_object/management_history/computer_usage_log.rb +24 -0
  50. data/lib/jss/api_object/management_history/ebook.rb +25 -0
  51. data/lib/jss/api_object/management_history/hashlike.rb +24 -0
  52. data/lib/jss/api_object/management_history/mac_app_store_app.rb +24 -0
  53. data/lib/jss/api_object/management_history/mdm_command.rb +24 -0
  54. data/lib/jss/api_object/management_history/mobile_device_app.rb +24 -0
  55. data/lib/jss/api_object/management_history/policy_log.rb +24 -0
  56. data/lib/jss/api_object/management_history/screen_sharing_log.rb +24 -0
  57. data/lib/jss/api_object/management_history/user_location_change.rb +24 -0
  58. data/lib/jss/api_object/matchable.rb +1 -1
  59. data/lib/jss/api_object/mdm.rb +1 -1
  60. data/lib/jss/api_object/mobile_device.rb +1 -1
  61. data/lib/jss/api_object/mobile_device_application.rb +1 -1
  62. data/lib/jss/api_object/netboot_server.rb +1 -1
  63. data/lib/jss/api_object/network_segment.rb +1 -1
  64. data/lib/jss/api_object/package.rb +1 -1
  65. data/lib/jss/api_object/patch_policy.rb +1 -1
  66. data/lib/jss/api_object/patch_source.rb +1 -1
  67. data/lib/jss/api_object/patch_source/patch_external_source.rb +1 -1
  68. data/lib/jss/api_object/patch_source/patch_internal_source.rb +1 -1
  69. data/lib/jss/api_object/patch_title.rb +1 -1
  70. data/lib/jss/api_object/patch_title/version.rb +1 -1
  71. data/lib/jss/api_object/peripheral.rb +1 -1
  72. data/lib/jss/api_object/peripheral_type.rb +1 -1
  73. data/lib/jss/api_object/policy.rb +1 -1
  74. data/lib/jss/api_object/purchasable.rb +1 -1
  75. data/lib/jss/api_object/removable_macaddr.rb +1 -1
  76. data/lib/jss/api_object/restricted_software.rb +24 -0
  77. data/lib/jss/api_object/scopable.rb +1 -1
  78. data/lib/jss/api_object/scopable/scope.rb +169 -155
  79. data/lib/jss/api_object/script.rb +1 -1
  80. data/lib/jss/api_object/self_servable.rb +1 -1
  81. data/lib/jss/api_object/self_servable/icon.rb +1 -1
  82. data/lib/jss/api_object/sitable.rb +1 -1
  83. data/lib/jss/api_object/site.rb +1 -1
  84. data/lib/jss/api_object/software_update_server.rb +1 -1
  85. data/lib/jss/api_object/updatable.rb +1 -1
  86. data/lib/jss/api_object/uploadable.rb +1 -1
  87. data/lib/jss/api_object/user.rb +1 -1
  88. data/lib/jss/api_object/vppable.rb +1 -1
  89. data/lib/jss/api_object/webhook.rb +1 -1
  90. data/lib/jss/client.rb +1 -1
  91. data/lib/jss/client/jamf_binary.rb +1 -1
  92. data/lib/jss/client/jamf_helper.rb +1 -1
  93. data/lib/jss/client/management_action.rb +1 -1
  94. data/lib/jss/compatibility.rb +1 -1
  95. data/lib/jss/composer.rb +1 -1
  96. data/lib/jss/configuration.rb +1 -1
  97. data/lib/jss/db_connection.rb +1 -1
  98. data/lib/jss/exceptions.rb +1 -1
  99. data/lib/jss/ruby_extensions.rb +1 -1
  100. data/lib/jss/ruby_extensions/array.rb +1 -1
  101. data/lib/jss/ruby_extensions/filetest.rb +1 -1
  102. data/lib/jss/ruby_extensions/hash.rb +1 -1
  103. data/lib/jss/ruby_extensions/ipaddr.rb +1 -1
  104. data/lib/jss/ruby_extensions/pathname.rb +1 -1
  105. data/lib/jss/ruby_extensions/string.rb +1 -1
  106. data/lib/jss/ruby_extensions/time.rb +1 -1
  107. data/lib/jss/server.rb +1 -1
  108. data/lib/jss/utility.rb +1 -1
  109. data/lib/jss/validate.rb +1 -1
  110. data/lib/jss/version.rb +2 -2
  111. data/lib/jss/xml_workaround.rb +1 -1
  112. data/lib/ruby-jss.rb +24 -0
  113. data/test/bin/runtests +1 -1
  114. data/test/lib/testhelper.rb +1 -1
  115. data/test/lib/testhelper/auth.rb +1 -1
  116. data/test/lib/testhelper/patch_mgmt.rb +1 -1
  117. data/test/specs/api_connection_spec.rb +1 -1
  118. data/test/specs/patch01_source_spec.rb +1 -1
  119. data/test/specs/patch02_internal_source_spec.rb +1 -1
  120. data/test/specs/patch03_external_source_spec.rb +1 -1
  121. data/test/specs/patch04_titles_spec.rb +1 -1
  122. data/test/specs/patch05_policies_spec.rb +1 -1
  123. data/test/specs/patch06_cleanup_spec.rb +1 -1
  124. data/test/specs/policy_spec.rb +1 -1
  125. metadata +2 -2
@@ -1,3 +1,27 @@
1
+ ### Copyright 2019 Pixar
2
+
3
+ ###
4
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ ### with the following modification; you may not use this file except in
6
+ ### compliance with the Apache License and the following modification to it:
7
+ ### Section 6. Trademarks. is deleted and replaced with:
8
+ ###
9
+ ### 6. Trademarks. This License does not grant permission to use the trade
10
+ ### names, trademarks, service marks, or product names of the Licensor
11
+ ### and its affiliates, except as required to comply with Section 4(c) of
12
+ ### the License and to reproduce the content of the NOTICE file.
13
+ ###
14
+ ### You may obtain a copy of the Apache License at
15
+ ###
16
+ ### http://www.apache.org/licenses/LICENSE-2.0
17
+ ###
18
+ ### Unless required by applicable law or agreed to in writing, software
19
+ ### distributed under the Apache License with the above modification is
20
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ ### KIND, either express or implied. See the Apache License for the specific
22
+ ### language governing permissions and limitations under the Apache License.
23
+ ###
24
+
1
25
  #
2
26
  module JSS
3
27
 
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Pixar
1
+ # Copyright 2019 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Pixar
1
+ # Copyright 2019 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,3 +1,27 @@
1
+ ### Copyright 2019 Pixar
2
+
3
+ ###
4
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ ### with the following modification; you may not use this file except in
6
+ ### compliance with the Apache License and the following modification to it:
7
+ ### Section 6. Trademarks. is deleted and replaced with:
8
+ ###
9
+ ### 6. Trademarks. This License does not grant permission to use the trade
10
+ ### names, trademarks, service marks, or product names of the Licensor
11
+ ### and its affiliates, except as required to comply with Section 4(c) of
12
+ ### the License and to reproduce the content of the NOTICE file.
13
+ ###
14
+ ### You may obtain a copy of the Apache License at
15
+ ###
16
+ ### http://www.apache.org/licenses/LICENSE-2.0
17
+ ###
18
+ ### Unless required by applicable law or agreed to in writing, software
19
+ ### distributed under the Apache License with the above modification is
20
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ ### KIND, either express or implied. See the Apache License for the specific
22
+ ### language governing permissions and limitations under the Apache License.
23
+ ###
24
+
1
25
  module JSS
2
26
 
3
27
  # Restricted Software items in the JSS.
@@ -1,4 +1,4 @@
1
- ### Copyright 2018 Pixar
1
+ ### Copyright 2019 Pixar
2
2
 
3
3
  ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Pixar
1
+ # Copyright 2019 Pixar
2
2
 
3
3
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  # with the following modification; you may not use this file except in
@@ -22,7 +22,6 @@
22
22
  #
23
23
  #
24
24
 
25
- #
26
25
  module JSS
27
26
 
28
27
  module Scopable
@@ -30,22 +29,17 @@ module JSS
30
29
  # Classes
31
30
  #####################################
32
31
 
32
+ # This class represents a Scope in the JSS, as can be applied to Scopable
33
+ # objects like Policies, Profiles, etc. Instances of this class are
34
+ # generally used as the value of the @scope attribute of those objects.
33
35
  #
34
- # This class represents a Scope in the JSS, as can be applied to Scopable objects like
35
- # Policies, Profiles, etc. Instances of this class are generally used as the value of the @scope attribute
36
- # of those objects.
37
- #
38
- # Scope data comes from the API as a hash within the overall object data. The main keys of the hash
39
- # define the included targets of the scope. A sub-hash defines limitations on those inclusions,
40
- # and another sub-hash defines explicit exclusions.
36
+ # Scope data comes from the API as a hash within the overall object data.
37
+ # The main keys of the hash define the included targets of the scope. A
38
+ # sub-hash defines limitations on those inclusions, and another sub-hash
39
+ # defines explicit exclusions.
41
40
  #
42
41
  # This class provides methods for adding, removing, or fully replacing the
43
- # various parts of the scope's inclusions, limitations, and exclusions.
44
- #
45
- # @todo Implement simple LDAP queries using the defined {LDAPServer}s to confirm the
46
- # existance of users or groups used in limitations and exclusions. As things are now
47
- # if you add invalid user or group names, you'll get a 409 conflict error when you try
48
- # to save your changes to the JSS.
42
+ # various items in scope's realms: targets, limitations, and exclusions.
49
43
  #
50
44
  # @see JSS::Scopable
51
45
  #
@@ -86,6 +80,9 @@ module JSS
86
80
  # their corresponding target group keys from SCOPING_CLASSES.
87
81
  TARGETS_AND_GROUPS = { computers: :computer_groups, mobile_devices: :mobile_device_groups }.freeze
88
82
 
83
+ # added to the ends of singular key names if needed, e.g. computer_group => computer_groups
84
+ ESS = 's'.freeze
85
+
89
86
  # These can be part of the base inclusion list of the scope,
90
87
  # along with the appropriate target and target group keys
91
88
  INCLUSIONS = %i[buildings departments].freeze
@@ -176,13 +173,13 @@ module JSS
176
173
  # If raw_scope is empty, a default scope, scoped to all targets, is created, and can be modified
177
174
  # as needed.
178
175
  #
179
- # @param target_key[Symbol] the kind of thing we're scopeing, one of {TARGETS_AND_GROUPS}
176
+ # @param target_key[Symbol] the kind of thing we're scoping, one of {TARGETS_AND_GROUPS}
180
177
  #
181
178
  # @param raw_scope[Hash] the JSON :scope data from an API query that is scopable, e.g. a Policy.
182
179
  #
183
180
  def initialize(target_key, raw_scope = nil)
184
181
  raw_scope ||= DEFAULT_SCOPE
185
- raise JSS::InvalidDataError, "The target class of a Scope must be one of the symbols :#{TARGETS_AND_GROUPS.keys.join(', :')}" unless TARGETS_AND_GROUPS.keys.include? target_key
182
+ raise JSS::InvalidDataError, "The target class of a Scope must be one of the symbols :#{TARGETS_AND_GROUPS.keys.join(', :')}" unless TARGETS_AND_GROUPS.key?(target_key)
186
183
 
187
184
  @target_key = target_key
188
185
  @target_class = SCOPING_CLASSES[@target_key]
@@ -195,19 +192,28 @@ module JSS
195
192
  @all_key = "all_#{target_key}".to_sym
196
193
  @all_targets = raw_scope[@all_key]
197
194
 
198
- # Everything gets mapped from an Array of Hashes to an Array of names (or an empty array)
199
- # since names are all that really matter when submitting the scope.
195
+ # Everything gets mapped from an Array of Hashes to
196
+ # an Array of ids
200
197
  @inclusions = {}
201
- @inclusion_keys.each { |k| @inclusions[k] = raw_scope[k] ? raw_scope[k].map { |n| n[:name] } : [] }
198
+ @inclusion_keys.each do |k|
199
+ raw_scope[k] ||= []
200
+ @inclusions[k] = raw_scope[k].compact.map { |n| n[:id].to_i }
201
+ end # @inclusion_keys.each do |k|
202
202
 
203
203
  @limitations = {}
204
204
  if raw_scope[:limitations]
205
- LIMITATIONS.each { |k| @limitations[k] = raw_scope[:limitations][k] ? raw_scope[:limitations][k].map { |n| n[:name] } : [] }
206
- end
205
+ LIMITATIONS.each do |k|
206
+ raw_scope[:limitations][k] ||= []
207
+ @limitations[k] = raw_scope[:limitations][k].compact.map { |n| n[:id].to_i }
208
+ end # LIMITATIONS.each do |k|
209
+ end # if raw_scope[:limitations]
207
210
 
208
211
  @exclusions = {}
209
212
  if raw_scope[:exclusions]
210
- @exclusion_keys.each { |k| @exclusions[k] = raw_scope[:exclusions][k] ? raw_scope[:exclusions][k].map { |n| n[:name] } : [] }
213
+ @exclusion_keys.each do |k|
214
+ raw_scope[:exclusions][k] ||= []
215
+ @exclusions[k] = raw_scope[:exclusions][k].compact.map { |n| n[:id].to_i }
216
+ end
211
217
  end
212
218
 
213
219
  @container = nil
@@ -246,7 +252,7 @@ module JSS
246
252
  # @param key[Symbol] the key from #{SCOPING_CLASSES} for the kind of items
247
253
  # being included, :computer, :building, etc...
248
254
  #
249
- # @param list[Array] the names of the items being added
255
+ # @param list[Array] identifiers of the items being added
250
256
  #
251
257
  # @example
252
258
  # set_targets(:computers, ['kimchi','mantis'])
@@ -254,56 +260,54 @@ module JSS
254
260
  # @return [void]
255
261
  #
256
262
  def set_targets(key, list)
257
- raise JSS::InvalidDataError, "Inclusion key must be one of :#{@inclusion_keys.join(', :')}" unless @inclusion_keys.include? key
258
- raise JSS::InvalidDataError, "List must be an Array of #{key} names, it may be empty." unless list.is_a? Array
263
+ key = pluralize_key(key)
264
+ raise JSS::InvalidDataError, "List must be an Array of #{key} identifiers, it may be empty." unless list.is_a? Array
265
+
266
+ # check the idents
267
+ list.map! do |ident|
268
+ item_id = validate_item(:target, key, ident)
269
+ if @exclusions[key] && @exclusions[key].include?(item_id)
270
+ raise JSS::AlreadyExistsError, \
271
+ "Can't set #{key} target to '#{ident}' because it's already an explicit exclusion."
272
+ end
273
+ item_id
274
+ end # each
259
275
 
260
276
  return nil if list.sort == @inclusions[key].sort
261
277
 
262
- # emptying the list?
263
- if list.empty?
264
- @inclusion[key] = list
265
- # if ALL the @inclusion keys are empty, then set all targets to true.
266
- @all_targets = @inclusions.values.reject { |a| a.nil? || a.empty? }.empty?
267
- @container.should_update if @container
268
- return list
269
- end
270
-
271
- # check the names
272
- list.each do |name|
273
- raise JSS::NoSuchItemError, "No existing #{key} with name '#{name}'" unless check_name key, name
274
- raise JSS::AlreadyExistsError, "Can't set #{key} scope to '#{name}' because it's already an explicit exclusion." if @exclusions[key] && @exclusions[key].include?(name)
275
- end # each
276
-
277
278
  @inclusions[key] = list
278
279
  @all_targets = false
279
280
  @container.should_update if @container
280
281
  end # sinclude_in_scope
282
+ alias set_target set_targets
281
283
  alias set_inclusion set_targets
284
+ alias set_inclusions set_targets
282
285
 
283
- # Add a single item a a target in this scope.
286
+ # Add a single item as a target in this scope.
284
287
  #
285
- # The item name will be checked for existence in the JSS, and an exception raised if the item doesn't exist.
288
+ # The item name will be checked for existence in the JSS, and an exception
289
+ # raised if the item doesn't exist.
286
290
  #
287
291
  # @param key[Symbol] the key from #{SCOPING_CLASSES} for the kind of item being added, :computer, :building, etc...
288
292
  #
289
- # @param item[String] the name of the item being added
293
+ # @param item[String,integer] a valid identifier of the item being added
290
294
  #
291
295
  # @example
292
- # add_target(:computer, "mantis")
296
+ # add_target(:computers, "mantis")
297
+ #
298
+ # @example
299
+ # add_target(:computer_groups, 2342)
293
300
  #
294
301
  # @return [void]
295
302
  #
296
303
  def add_target(key, item)
297
- raise JSS::InvalidDataError, "Inclusion key must be one of :#{@inclusion_keys.join(', :')}" unless @inclusion_keys.include? key
298
- raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.is_a? String
304
+ key = pluralize_key(key)
305
+ item_id = validate_item(:target, key, item)
306
+ return if @inclusions[key] && @inclusions[key].include?(item_id)
299
307
 
300
- return nil if @inclusions[key] && @inclusions[key].include?(item)
308
+ raise JSS::AlreadyExistsError, "Can't set #{key} target to '#{item}' because it's already an explicit exclusion." if @exclusions[key] && @exclusions[key].include?(item_id)
301
309
 
302
- # check the name
303
- raise JSS::NoSuchItemError, "No existing #{key} with name '#{item}'" unless check_name key, item
304
- raise JSS::AlreadyExistsError, "Can't set #{key} scope to '#{item}' because it's already an explicit exclusion." if @exclusions[key] && @exclusions[key].include?(item)
305
-
306
- @inclusions[key] << item
310
+ @inclusions[key] << item_id
307
311
  @all_targets = false
308
312
  @container.should_update if @container
309
313
  end
@@ -313,7 +317,7 @@ module JSS
313
317
  #
314
318
  # @param key[Symbol] the key from #{SCOPING_CLASSES} for the kind of item being removed, :computer, :building, etc...
315
319
  #
316
- # @param item[String] the name of the item being removed
320
+ # @param item[String,integer] a valid identifier of the item being removed
317
321
  #
318
322
  # @example
319
323
  # remove_target(:computer, "mantis")
@@ -321,16 +325,11 @@ module JSS
321
325
  # @return [void]
322
326
  #
323
327
  def remove_target(key, item)
324
- raise JSS::InvalidDataError, "Inclusion key must be one of :#{@inclusion_keys.join(', :')}" unless @inclusion_keys.include? key
325
- raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.is_a? String
326
-
327
- return nil unless @inclusions[key] && @inclusions[key].include?(item)
328
-
329
- @inclusions[key] -= [item]
330
-
331
- # if ALL the @inclusion keys are empty, then set all targets to true.
332
- @all_targets = @inclusions.values.reject { |a| a.nil? || a.empty? }.empty?
333
-
328
+ key = pluralize_key(key)
329
+ item_id = validate_item :target, key, item, error_if_not_found: false
330
+ return unless item_id
331
+ return unless @inclusions[key] && @inclusions[key].include?(item_id)
332
+ @inclusions[key].delete item_id
334
333
  @container.should_update if @container
335
334
  end
336
335
  alias remove_inclusion remove_target
@@ -342,35 +341,32 @@ module JSS
342
341
  #
343
342
  # @param key[Symbol] the type of items being set as limitations, :network_segments, :users, etc...
344
343
  #
345
- # @param list[Array] the names of the items being set as limitations
344
+ # @param list[Array] the identifiers of the items being set as limitations
346
345
  #
347
346
  # @example
348
- # set_limitation(:network_segments, ['foo','bar'])
347
+ # set_limitation(:network_segments, ['foo',231])
349
348
  #
350
349
  # @return [void]
351
350
  #
352
351
  # @todo handle ldap user group lookups
353
352
  #
354
353
  def set_limitation(key, list)
355
- raise JSS::InvalidDataError, "Limitation key must be one of :#{LIMITATIONS.join(', :')}" unless LIMITATIONS.include? key
356
- raise JSS::InvalidDataError, "List must be an Array of #{key} names, it may be empty." unless list.is_a? Array
357
- return nil if list.sort == @limitations[key].sort
358
-
359
- if list.empty?
360
- @limitations[key] = []
361
- @container.should_update if @container
362
- return list
363
- end
364
-
365
- # check the names
366
- list.each do |name|
367
- raise JSS::NoSuchItemError, "No existing #{key} with name '#{name}'" unless check_name key, name
368
- raise JSS::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion." if @exclusions[key] && @exclusions[key].include?(name)
354
+ key = pluralize_key(key)
355
+ raise JSS::InvalidDataError, "List must be an Array of #{key} identifiers, it may be empty." unless list.is_a? Array
356
+
357
+ # check the idents
358
+ list.map! do |ident|
359
+ item_id = validate_item(:limitation, key, ident)
360
+ raise JSS::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion." if @exclusions[key] && @exclusions[key].include?(item_id)
361
+ item_id
369
362
  end # each
370
363
 
364
+ return nil if list.sort == @limitations[key].sort
365
+
371
366
  @limitations[key] = list
372
367
  @container.should_update if @container
373
- end # limit scope
368
+ end # set_limitation
369
+ alias set_limitations set_limitation
374
370
 
375
371
  # Add a single item for limiting this scope.
376
372
  #
@@ -378,7 +374,7 @@ module JSS
378
374
  #
379
375
  # @param key[Symbol] the type of item being added, :computer, :building, etc...
380
376
  #
381
- # @param item[String] the name of the item being added
377
+ # @param item[String,integer] a valid identifier of the item being added
382
378
  #
383
379
  # @example
384
380
  # add_limitation(:network_segments, "foo")
@@ -388,16 +384,13 @@ module JSS
388
384
  # @todo handle ldap user/group lookups
389
385
  #
390
386
  def add_limitation(key, item)
391
- raise JSS::InvalidDataError, "Limitation key must be one of :#{LIMITATIONS.join(', :')}" unless LIMITATIONS.include? key
392
- raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.is_a? String
393
-
394
- return nil if @limitations[key] && @limitations[key].include?(item)
387
+ key = pluralize_key(key)
388
+ item_id = validate_item(:limitation, key, item)
389
+ return nil if @limitations[key] && @limitations[key].include?(item_id)
395
390
 
396
- # check the name
397
- raise JSS::NoSuchItemError, "No existing #{key} with name '#{item}'" unless check_name key, item
398
- raise JSS::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion." if @exclusions[key] && @exclusions[key].include?(item)
391
+ raise JSS::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion." if @exclusions[key] && @exclusions[key].include?(item_id)
399
392
 
400
- @limitations[key] << item
393
+ @limitations[key] << item_id
401
394
  @container.should_update if @container
402
395
  end
403
396
 
@@ -405,7 +398,7 @@ module JSS
405
398
  #
406
399
  # @param key[Symbol] the type of item being removed, :computer, :building, etc...
407
400
  #
408
- # @param item[String] the name of the item being removed
401
+ # @param item[String,integer] a valid identifier of the item being removed
409
402
  #
410
403
  # @example
411
404
  # remove_limitation(:network_segments, "foo")
@@ -415,12 +408,11 @@ module JSS
415
408
  # @todo handle ldap user/group lookups
416
409
  #
417
410
  def remove_limitation(key, item)
418
- raise JSS::InvalidDataError, "Limitation key must be one of :#{LIMITATIONS.join(', :')}" unless LIMITATIONS.include? key
419
- raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.is_a? String
420
-
421
- return nil unless @limitations[key] && @limitations[key].include?(item)
422
-
423
- @limitations[key] -= [item]
411
+ key = pluralize_key(key)
412
+ item_id = validate_item :limitation, key, item, error_if_not_found: false
413
+ return unless item_id
414
+ return unless @limitations[key] && @limitations[key].include?(item_id)
415
+ @limitations[key].delete item_id
424
416
  @container.should_update if @container
425
417
  end ###
426
418
 
@@ -431,7 +423,7 @@ module JSS
431
423
  #
432
424
  # @param key[Symbol] the type of item being excluded, :computer, :building, etc...
433
425
  #
434
- # @param list[Array] the names of the items being added
426
+ # @param list[Array] the identifiers of the items being set
435
427
  #
436
428
  # @example
437
429
  # set_exclusion(:network_segments, ['foo','bar'])
@@ -439,27 +431,23 @@ module JSS
439
431
  # @return [void]
440
432
  #
441
433
  def set_exclusion(key, list)
442
- raise JSS::InvalidDataError, "Exclusion key must be one of :#{@exclusion_keys.join(', :')}" unless @exclusion_keys.include? key
443
- raise JSS::InvalidDataError, "List must be an Array of #{key} names, it may be empty." unless list.is_a? Array
444
- return nil if list.sort == @exclusions[key].sort
445
-
446
- if list.empty?
447
- @exclusions[key] = []
448
- @container.should_update if @container
449
- return list
450
- end
434
+ key = pluralize_key(key)
435
+ raise JSS::InvalidDataError, "List must be an Array of #{key} identifiers, it may be empty." unless list.is_a? Array
451
436
 
452
- # check the names
453
- list.each do |name|
454
- raise JSS::NoSuchItemError, "No existing #{key} with name '#{name}'" unless check_name key, name
437
+ # check the idents
438
+ list.map! do |ident|
439
+ item_id = validate_item(:exclusion, key, ident)
455
440
  case key
456
441
  when *@inclusion_keys
457
- raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{name}' because it's already explicitly included." if @inclusions[key] && @inclusions[key].include?(name)
442
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{ident}' because it's already explicitly included." if @inclusions[key] && @inclusions[key].include?(item_id)
458
443
  when *LIMITATIONS
459
- raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{name}' because it's already an explicit limitation." if @limitations[key] && @limitations[key].include?(name)
444
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{ident}' because it's already an explicit limitation." if @limitations[key] && @limitations[key].include?(item_id)
460
445
  end
446
+ item_id
461
447
  end # each
462
448
 
449
+ return nil if list.sort == @exclusions[key].sort
450
+
463
451
  @exclusions[key] = list
464
452
  @container.should_update if @container
465
453
  end # limit scope
@@ -470,7 +458,7 @@ module JSS
470
458
  #
471
459
  # @param key[Symbol] the type of item being added to the exclusions, :computer, :building, etc...
472
460
  #
473
- # @param item[String] the name of the item being added
461
+ # @param item[String,integer] a valid identifier of the item being added
474
462
  #
475
463
  # @example
476
464
  # add_exclusion(:network_segments, "foo")
@@ -478,17 +466,13 @@ module JSS
478
466
  # @return [void]
479
467
  #
480
468
  def add_exclusion(key, item)
481
- raise JSS::InvalidDataError, "Exclusion key must be one of :#{@exclusion_keys.join(', :')}" unless @exclusion_keys.include? key
482
- raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.is_a? String
483
-
484
- return nil if @exclusions[key] && @exclusions[key].include?(item)
485
-
486
- # check the name
487
- raise JSS::NoSuchItemError, "No existing #{key} with name '#{item}'" unless check_name key, item
469
+ key = pluralize_key(key)
470
+ item_id = validate_item(:exclusion, key, item)
471
+ return if @exclusions[key] && @exclusions[key].include?(item_id)
488
472
  raise JSS::AlreadyExistsError, "Can't exclude #{key} scope to '#{item}' because it's already explicitly included." if @inclusions[key] && @inclusions[key].include?(item)
489
473
  raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{item}' because it's already an explicit limitation." if @limitations[key] && @limitations[key].include?(item)
490
474
 
491
- @exclusions[key] << item
475
+ @exclusions[key] << item_id
492
476
  @container.should_update if @container
493
477
  end
494
478
 
@@ -496,7 +480,7 @@ module JSS
496
480
  #
497
481
  # @param key[Symbol] the type of item being removed from the excludions, :computer, :building, etc...
498
482
  #
499
- # @param item[String] the name of the item being removed
483
+ # @param item[String,integer] a valid identifier of the item being removed
500
484
  #
501
485
  # @example
502
486
  # remove_exclusion(:network_segments, "foo")
@@ -504,12 +488,10 @@ module JSS
504
488
  # @return [void]
505
489
  #
506
490
  def remove_exclusion(key, item)
507
- raise JSS::InvalidDataError, "Exclusion key must be one of :#{@exclusion_keys.join(', :')}" unless @exclusion_keys.include? key
508
- raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.is_a? String
509
-
510
- return nil unless @exclusions[key] && @exclusions[key].include?(item)
511
-
512
- @exclusions[key] -= [item]
491
+ key = pluralize_key(key)
492
+ item_id = validate_item :exclusion, key, item, error_if_not_found: false
493
+ return unless @exclusions[key] && @exclusions[key].include?(item_id)
494
+ @exclusions[key].delete item_id
513
495
  @container.should_update if @container
514
496
  end
515
497
 
@@ -524,24 +506,42 @@ module JSS
524
506
  scope.add_element(@all_key.to_s).text = @all_targets
525
507
 
526
508
  @inclusions.each do |klass, list|
527
- list_as_hash = list.map { |i| { name: i } }
528
- scope << SCOPING_CLASSES[klass].xml_list(list_as_hash, :name)
509
+ list.compact!
510
+ list.delete 0
511
+ list_as_hash = list.map { |i| { id: i } }
512
+ scope << SCOPING_CLASSES[klass].xml_list(list_as_hash, :id)
529
513
  end
530
514
 
531
515
  limitations = scope.add_element('limitations')
532
516
  @limitations.each do |klass, list|
533
- list_as_hash = list.map { |i| { name: i } }
534
- limitations << SCOPING_CLASSES[klass].xml_list(list_as_hash, :name)
517
+ list.compact!
518
+ list.delete 0
519
+ list_as_hash = list.map { |i| { id: i } }
520
+ limitations << SCOPING_CLASSES[klass].xml_list(list_as_hash, :id)
535
521
  end
536
522
 
537
523
  exclusions = scope.add_element('exclusions')
538
524
  @exclusions.each do |klass, list|
539
- list_as_hash = list.map { |i| { name: i } }
540
- exclusions << SCOPING_CLASSES[klass].xml_list(list_as_hash, :name)
525
+ list.compact!
526
+ list.delete 0
527
+ list_as_hash = list.map { |i| { id: i } }
528
+ exclusions << SCOPING_CLASSES[klass].xml_list(list_as_hash, :id)
541
529
  end
542
530
  scope
543
531
  end # scope_xml
544
532
 
533
+ # Remove the init_data and api object from
534
+ # the instance_variables used to create
535
+ # pretty-print (pp) output.
536
+ #
537
+ # @return [Array] the desired instance_variables
538
+ #
539
+ def pretty_print_instance_variables
540
+ vars = instance_variables.sort
541
+ vars.delete :@container
542
+ vars
543
+ end
544
+
545
545
  # Aliases
546
546
 
547
547
  alias all_targets? all_targets
@@ -550,29 +550,43 @@ module JSS
550
550
  #####################################
551
551
  private
552
552
 
553
- # Given a name of some class of item to be used in the scope, check that it
554
- # exists in the JSS.
553
+ # look up a valid id or nil, for use in a scope type
555
554
  #
556
- # @return [Boolean] does the name exist for the key in JSS or LDAP?
555
+ # @param realm [Symbol] How is this key being used in the scope?
556
+ # :target, :limitation, or :exclusion
557
557
  #
558
- def check_name(key, name)
559
- found_in_jss = SCOPING_CLASSES[key].all_names(api: container.api).include?(name)
560
-
561
- return true if found_in_jss
562
-
563
- return false unless CHECK_LDAP_KEYS.include?(key)
564
-
565
- begin
566
- return JSS::LDAPServer.user_in_ldap?(name, api: container.api) if LDAP_USER_KEYS.include?(key)
567
- return JSS::LDAPServer.group_in_ldap?(name, api: container.api) if LDAP_GROUP_KEYS.include?(key)
568
-
569
- # if an ldap server isn't connected, make a note of it and return true
570
- rescue JSS::InvalidConnectionError
571
- @unable_to_verify_ldap_entries = true
572
- return true
573
- end # begin
574
-
575
- false
558
+ # @param key [Symbol] What kind of thing are we adding to the scope?
559
+ # e.g computer, network_segment, etc.
560
+ #
561
+ # @param ident [String, Integer] A unique identifier for the item being
562
+ # validated, jss id, name, serial number, etc.
563
+ #
564
+ # @return [Integer, nil] the valid id for the item, or nil if not found
565
+ #
566
+ def validate_item(realm, key, ident, error_if_not_found: true)
567
+ # which keys allowed depends on how the item is used...
568
+ possible_keys =
569
+ case realm
570
+ when :target then @inclusion_keys
571
+ when :limitation then LIMITATIONS
572
+ when :exclusion then @exclusion_keys
573
+ else
574
+ raise ArgumentError, 'Unknown realm, must be :target, :limitation, or :exclusion'
575
+ end
576
+ key = pluralize_key(key)
577
+ raise JSS::InvalidDataError, "#{realm} key must be one of :#{possible_keys.join(', :')}" \
578
+ unless possible_keys.include? key
579
+
580
+ # return nil or a valid id
581
+ id = SCOPING_CLASSES[key].valid_id ident
582
+ raise JSS::NoSuchItemError, "No existing #{key} matching '#{ident}'" if error_if_not_found && id.nil?
583
+ id
584
+ end # validate_item(type, key, ident)
585
+
586
+ # the symbols used in the API data are plural, e.g. 'network_segments'
587
+ # this will pluralize them, allowing us to use singulars as well.
588
+ def pluralize_key(key)
589
+ key.to_s.end_with?(ESS) ? key : "#{key}s".to_sym
576
590
  end
577
591
 
578
592
  end # class Scope