windoo 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES.md +9 -0
- data/LICENSE.txt +177 -0
- data/README.md +222 -0
- data/lib/windoo/base_classes/array_manager.rb +335 -0
- data/lib/windoo/base_classes/criteria_manager.rb +327 -0
- data/lib/windoo/base_classes/criterion.rb +226 -0
- data/lib/windoo/base_classes/json_object.rb +472 -0
- data/lib/windoo/configuration.rb +221 -0
- data/lib/windoo/connection/actions.rb +152 -0
- data/lib/windoo/connection/attributes.rb +156 -0
- data/lib/windoo/connection/connect.rb +402 -0
- data/lib/windoo/connection/constants.rb +55 -0
- data/lib/windoo/connection/token.rb +489 -0
- data/lib/windoo/connection.rb +92 -0
- data/lib/windoo/converters.rb +31 -0
- data/lib/windoo/exceptions.rb +34 -0
- data/lib/windoo/mixins/api_collection.rb +408 -0
- data/lib/windoo/mixins/constants.rb +43 -0
- data/lib/windoo/mixins/default_connection.rb +75 -0
- data/lib/windoo/mixins/immutable.rb +34 -0
- data/lib/windoo/mixins/loading.rb +38 -0
- data/lib/windoo/mixins/patch/component.rb +102 -0
- data/lib/windoo/mixins/software_title/extension_attribute.rb +106 -0
- data/lib/windoo/mixins/utility.rb +23 -0
- data/lib/windoo/objects/capability.rb +82 -0
- data/lib/windoo/objects/capability_manager.rb +52 -0
- data/lib/windoo/objects/component.rb +99 -0
- data/lib/windoo/objects/component_criteria_manager.rb +26 -0
- data/lib/windoo/objects/component_criterion.rb +66 -0
- data/lib/windoo/objects/extension_attribute.rb +149 -0
- data/lib/windoo/objects/kill_app.rb +92 -0
- data/lib/windoo/objects/kill_app_manager.rb +89 -0
- data/lib/windoo/objects/patch.rb +235 -0
- data/lib/windoo/objects/patch_manager.rb +240 -0
- data/lib/windoo/objects/requirement.rb +85 -0
- data/lib/windoo/objects/requirement_manager.rb +52 -0
- data/lib/windoo/objects/software_title.rb +407 -0
- data/lib/windoo/validate.rb +548 -0
- data/lib/windoo/version.rb +15 -0
- data/lib/windoo/zeitwerk_config.rb +158 -0
- data/lib/windoo.rb +56 -0
- metadata +141 -0
@@ -0,0 +1,335 @@
|
|
1
|
+
# Copyright 2025 Pixar
|
2
|
+
#
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
4
|
+
# at the root of this project.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
# main module
|
9
|
+
module Windoo
|
10
|
+
|
11
|
+
module BaseClasses
|
12
|
+
|
13
|
+
# The common code for dealing with a managed array of objects in
|
14
|
+
# Software Titles.
|
15
|
+
#
|
16
|
+
# Array Managers manage an Array of instances of API objects, preventing
|
17
|
+
# direct access to the Array, but providing methods for adding, removing,
|
18
|
+
# updating, and moving array members, while appropriatly interacting with the
|
19
|
+
# API and maintaining consistency between the local Array and the server.
|
20
|
+
#
|
21
|
+
# This base class provides management of the actual Array, and doesn't
|
22
|
+
# intentionally communicate with the server at all. However, it
|
23
|
+
# may cause server interaction when calling methods on the objects held
|
24
|
+
# in the Array.
|
25
|
+
#
|
26
|
+
# Instances of subclasses of this class are held by API objects instead
|
27
|
+
# of the raw Array.
|
28
|
+
#
|
29
|
+
# For example, SoftwareTitles have a #patches method, which is a list
|
30
|
+
# of all the patches for the title. In the raw API data Hash, the :patches
|
31
|
+
# key contains an array of hashes of patch data.
|
32
|
+
#
|
33
|
+
# However, the SoftwareTitle#patches method does not return an Array.
|
34
|
+
# Intead it returns an instance of Windoo::PatchManager, a subclass of this class,
|
35
|
+
# which provides ways to add, update, and delete patches from the title.
|
36
|
+
#
|
37
|
+
# CAUTION: Do not instantiate (with .create) or delete members of the Array
|
38
|
+
# directly, use the `add_*` and `delete_` methods of the Array Manager, so
|
39
|
+
# that the local array automatically stays in sync with the server.
|
40
|
+
#
|
41
|
+
# TODO: Prevent instantiation of those objects outside of approved methods.
|
42
|
+
#
|
43
|
+
# Subclasses MUST define the constant MEMBER_CLASS to indicate the class of
|
44
|
+
# the items we are managing
|
45
|
+
#
|
46
|
+
class ArrayManager
|
47
|
+
|
48
|
+
# Constants
|
49
|
+
##################################
|
50
|
+
##################################
|
51
|
+
|
52
|
+
PP_OMITTED_INST_VARS = %i[@container].freeze
|
53
|
+
|
54
|
+
# Attributes
|
55
|
+
##################################
|
56
|
+
##################################
|
57
|
+
|
58
|
+
# @return [APICollection] the API object that contains this manager
|
59
|
+
attr_reader :container
|
60
|
+
|
61
|
+
# Constructor
|
62
|
+
##################################
|
63
|
+
##################################
|
64
|
+
|
65
|
+
# @param data [Array<Hash>] A JSON array of hashes from the API
|
66
|
+
# containing data the to construct one of these manager objects.
|
67
|
+
#
|
68
|
+
# @param container [Object] the object that contains this managed
|
69
|
+
# array of criteria
|
70
|
+
#
|
71
|
+
def initialize(data, container:)
|
72
|
+
@container = container
|
73
|
+
@managed_array = []
|
74
|
+
return unless data
|
75
|
+
|
76
|
+
@managed_array = data.map do |member_data|
|
77
|
+
self.class::MEMBER_CLASS.instantiate_from_container(container: container, **member_data)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Public Instance Methods
|
82
|
+
##################################
|
83
|
+
##################################
|
84
|
+
|
85
|
+
# Only selected items are displayed with prettyprint
|
86
|
+
# otherwise its too much data in irb.
|
87
|
+
#
|
88
|
+
# @return [Array] the desired instance_variables
|
89
|
+
#
|
90
|
+
###########################
|
91
|
+
def pretty_print_instance_variables
|
92
|
+
instance_variables - PP_OMITTED_INST_VARS
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [Array<Windoo::BaseClasses::Criterion>] A dup'd and frozen copy of
|
96
|
+
# the array of criteria maintained by this class
|
97
|
+
###########################
|
98
|
+
def to_a
|
99
|
+
@managed_array.dup.freeze
|
100
|
+
end
|
101
|
+
|
102
|
+
# Some convenience wrappers for common array methods
|
103
|
+
# For other array methods, use #to_a to get the
|
104
|
+
# actual (readonly dup of) the array.
|
105
|
+
#####
|
106
|
+
|
107
|
+
# @return [Object]
|
108
|
+
###########################
|
109
|
+
def [](idx)
|
110
|
+
@managed_array[idx]
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [Object]
|
114
|
+
###########################
|
115
|
+
def first
|
116
|
+
@managed_array.first
|
117
|
+
end
|
118
|
+
|
119
|
+
# @return [Object]
|
120
|
+
###########################
|
121
|
+
def last
|
122
|
+
@managed_array.last
|
123
|
+
end
|
124
|
+
|
125
|
+
# @return [Boolean]
|
126
|
+
###########################
|
127
|
+
def empty?
|
128
|
+
@managed_array.empty?
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return [Integer]
|
132
|
+
###########################
|
133
|
+
def size
|
134
|
+
@managed_array.size
|
135
|
+
end
|
136
|
+
alias count size
|
137
|
+
alias length size
|
138
|
+
|
139
|
+
# Iterators - they have to use the
|
140
|
+
# frozen dup from to_a, since they
|
141
|
+
# might try to modify items as they
|
142
|
+
# iterate.
|
143
|
+
###########################
|
144
|
+
|
145
|
+
# @return [Array]
|
146
|
+
###########################
|
147
|
+
def each(&block)
|
148
|
+
to_a.each(&block)
|
149
|
+
end
|
150
|
+
|
151
|
+
# @return [Object, nil]
|
152
|
+
###########################
|
153
|
+
def find(if_none = nil, &block)
|
154
|
+
to_a.find if_none, &block
|
155
|
+
end
|
156
|
+
|
157
|
+
# @return [Object, nil]
|
158
|
+
###########################
|
159
|
+
def find_by_attr(attr_name, value)
|
160
|
+
return if empty?
|
161
|
+
return unless @managed_array.first.respond_to? attr_name
|
162
|
+
|
163
|
+
@managed_array.find { |i| i.send(attr_name) == value }
|
164
|
+
end
|
165
|
+
|
166
|
+
# @return [Integer, nil]
|
167
|
+
###########################
|
168
|
+
def index(obj = nil, &block)
|
169
|
+
return to_a.index(obj) if obj
|
170
|
+
|
171
|
+
to_a.index(&block)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Private Instance Methods
|
175
|
+
##################################
|
176
|
+
##################################
|
177
|
+
private
|
178
|
+
|
179
|
+
# Add a member to the array at a given position.
|
180
|
+
#
|
181
|
+
# Subclasses must define a related method to create the new member
|
182
|
+
# object, then call this method to add it to the array, then do any
|
183
|
+
# other processing needed after, e.g. returning some attribute of
|
184
|
+
# the object.
|
185
|
+
#
|
186
|
+
# NOTE: This method does not communicate with the server. You must add
|
187
|
+
# the object to the server in whatever method calls this one, preferably
|
188
|
+
# before calling this one, so that any server errors are raised before
|
189
|
+
# we insert the object into the array.
|
190
|
+
#
|
191
|
+
# @param new_member [Object] the object to be added to the array
|
192
|
+
#
|
193
|
+
# @param index [Integer] The array index at which to add the object.
|
194
|
+
# Defaults to -1 (the end of the array)
|
195
|
+
#
|
196
|
+
# @return [Object] the object that was added
|
197
|
+
#
|
198
|
+
###########################
|
199
|
+
def add_member(new_member, index: -1)
|
200
|
+
@managed_array.insert index, new_member
|
201
|
+
new_member
|
202
|
+
end
|
203
|
+
|
204
|
+
# Update the details of an existing array member
|
205
|
+
#
|
206
|
+
# Subclasses should define a related method to do any kind of non-standard
|
207
|
+
# processing if needed, then call this method, perhaps after modifying the
|
208
|
+
# given attribs hash.
|
209
|
+
#
|
210
|
+
# This method will then call the matching setter method for each attrib
|
211
|
+
# provided, if available, passing in the new value.
|
212
|
+
#
|
213
|
+
# Those setters may or may not update the server immediately.
|
214
|
+
#
|
215
|
+
# @param id [Integer] The primary ID of the object to update.
|
216
|
+
# For an array of Windoo::Requirement, you would provide a value that is a
|
217
|
+
# 'requirementId', for an array of Windoo::Patch, the value would
|
218
|
+
# be a 'patchId'.
|
219
|
+
#
|
220
|
+
# @param attribs [Hash] Key=>value pairs for attributes to be updated
|
221
|
+
# and the new values to be applied.
|
222
|
+
# Each key will be transformed into a setter method and sent to the
|
223
|
+
# object with the value as input to the setter.
|
224
|
+
#
|
225
|
+
# If any special handling of an attrib is needed, the calling
|
226
|
+
# method should deal with that and modify the attribs hash
|
227
|
+
# before passing them into this method via #super.
|
228
|
+
#
|
229
|
+
# NOTE: Explicit nils are sent!
|
230
|
+
#
|
231
|
+
#
|
232
|
+
# @return [Object] the object that was updated
|
233
|
+
#
|
234
|
+
###########################
|
235
|
+
def update_member(id, **attribs)
|
236
|
+
member = member_by_id(id)
|
237
|
+
|
238
|
+
attribs.each do |attr_name, new_val|
|
239
|
+
setter = "#{attr_name}="
|
240
|
+
member.send setter, new_val if member.respond_to? setter
|
241
|
+
end
|
242
|
+
|
243
|
+
member
|
244
|
+
end
|
245
|
+
|
246
|
+
# Move a member to a new location in the array. This
|
247
|
+
# does not talk to the server
|
248
|
+
#
|
249
|
+
# @param member [Object] the member to move
|
250
|
+
#
|
251
|
+
# @param index [Integer] the new index for the member
|
252
|
+
#
|
253
|
+
# @return [void]
|
254
|
+
###########################
|
255
|
+
def move_member(member, index:)
|
256
|
+
curr_idx = @managed_array.index { |m| m == member }
|
257
|
+
|
258
|
+
@managed_array.insert index, @managed_array.delete_at(curr_idx)
|
259
|
+
end
|
260
|
+
|
261
|
+
# Delete a member of the array.
|
262
|
+
#
|
263
|
+
# This method will call the object's #delete method, if it has one,
|
264
|
+
# which may delete it from the server. It will then delete it from
|
265
|
+
# the local array
|
266
|
+
#
|
267
|
+
# Subclasses should define a related method that calls this one, doing
|
268
|
+
# any processing before or after
|
269
|
+
#
|
270
|
+
# @param id [Integer] The primary ID of the object to delete.
|
271
|
+
# For an array of Windoo::Requirement, you would provide a value that is a
|
272
|
+
# 'requirementId', for an array of Windoo::Patch, the value would
|
273
|
+
# be a 'patchId'.
|
274
|
+
#
|
275
|
+
# @return [Object] The object that was removed from the array
|
276
|
+
#
|
277
|
+
###########################
|
278
|
+
def delete_member(id)
|
279
|
+
member = member_by_id(id)
|
280
|
+
|
281
|
+
# call its delete method, which may delete it from the server
|
282
|
+
member.delete if member.respond_to? :delete
|
283
|
+
|
284
|
+
# delete from the array
|
285
|
+
@managed_array.delete member
|
286
|
+
|
287
|
+
member
|
288
|
+
end
|
289
|
+
|
290
|
+
# Delete all members of the array
|
291
|
+
#
|
292
|
+
# Subclasses should override, or define a related method that calls this one,
|
293
|
+
# doing any processing before or after
|
294
|
+
#
|
295
|
+
# @return [void]
|
296
|
+
#
|
297
|
+
###########################
|
298
|
+
def delete_all_members
|
299
|
+
@managed_array.each { |member| member.delete if member.respond_to? :delete }
|
300
|
+
@managed_array = []
|
301
|
+
end
|
302
|
+
|
303
|
+
# Return a member of the array by searching for its 'primary_id'
|
304
|
+
#
|
305
|
+
# @param id [Integer] The primary ID of the object to return.
|
306
|
+
# For an array of Windoo::Requirement, you would provide a value that is a
|
307
|
+
# 'requirementId', for an array of Windoo::Patch, the value would
|
308
|
+
# be a 'patchId'.
|
309
|
+
#
|
310
|
+
# @return [Object] The object with the given id
|
311
|
+
#
|
312
|
+
###########################
|
313
|
+
def member_by_id(id)
|
314
|
+
member = @managed_array.find { |m| m.send(primary_id_key) == id }
|
315
|
+
return member if member
|
316
|
+
|
317
|
+
raise Windoo::NoSuchItemError, "No matching #{self.class::MEMBER_CLASS} with #{primary_id_key} #{id} found"
|
318
|
+
end
|
319
|
+
|
320
|
+
# The primary
|
321
|
+
###########################
|
322
|
+
def primary_id_key
|
323
|
+
@primary_id_key ||= self.class::MEMBER_CLASS.primary_id_key
|
324
|
+
end
|
325
|
+
|
326
|
+
###########################
|
327
|
+
def container_primary_id_key
|
328
|
+
@container_primary_id_key ||= @container.class.primary_id_key
|
329
|
+
end
|
330
|
+
|
331
|
+
end # class Criterion
|
332
|
+
|
333
|
+
end # module BaseClasses
|
334
|
+
|
335
|
+
end # module Windoo
|
@@ -0,0 +1,327 @@
|
|
1
|
+
# Copyright 2025 Pixar
|
2
|
+
#
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
4
|
+
# at the root of this project.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
# main module
|
9
|
+
module Windoo
|
10
|
+
|
11
|
+
module BaseClasses
|
12
|
+
|
13
|
+
# The common code for dealing with a group of criteria-based objects
|
14
|
+
# in Software Titles.
|
15
|
+
#
|
16
|
+
# This class manages an array of instances of subclasses of
|
17
|
+
# {Windoo::BaseClasses::Criterion}
|
18
|
+
#
|
19
|
+
# See also: {Windoo::BaseClasses::ArrayManager}
|
20
|
+
# for info about managed Arrays.
|
21
|
+
#
|
22
|
+
# This class should be the superclass of classes representing
|
23
|
+
# the three ways Criteria are used in a {SoftwareTitle}.
|
24
|
+
#
|
25
|
+
# - SoftwareTitles have 'requirements'
|
26
|
+
# - These are criteria defining which computers have any version of the title installed.
|
27
|
+
# - {Patch Patches} within SoftwareTitles have 'capabilities'
|
28
|
+
# - These are criteria defining which computers are capable of installing/running the patch.
|
29
|
+
# - A Patch's '{Component component}' has a set of 'criteria'
|
30
|
+
# - These are criteria defining which comptuers have _this_ version of the title installed.
|
31
|
+
#
|
32
|
+
# Here's how that looks for requirements:
|
33
|
+
#
|
34
|
+
# - {Windoo::RequirementManager Windoo::RequirementManager} should be a subclass of this class, and must define<br/>
|
35
|
+
# the constant `MEMBER_CLASS = Windoo::Requirement` indicating that it should manage an array of...
|
36
|
+
# - {Windoo::Requirement Windoo::Requirement} objects which is a subclass of {Windoo::BaseClasses::Criterion}
|
37
|
+
# - {Windoo::SoftwareTitle#requirements} should return a single {Windoo::RequirementManager Windoo::RequirementManager} object
|
38
|
+
#
|
39
|
+
# Here's how to use a {Windoo::RequirementManager Windoo::RequirementManager}:
|
40
|
+
#
|
41
|
+
# title = Windoo::SoftwareTitle.fetch 'mytitle'
|
42
|
+
# title.requirements.to_a
|
43
|
+
# # => the readonly Array of Windoo::Requirement objects
|
44
|
+
#
|
45
|
+
# title.requirements.add_criterion(options: here)
|
46
|
+
# # => add a new Windoo::Requirement to the Array
|
47
|
+
#
|
48
|
+
# title.requirements.replace_criterion(victim_id, options: here)
|
49
|
+
# # => replace an existing Windoo::Requirement in the Array
|
50
|
+
#
|
51
|
+
# title.requirements.delete_criterion(victim_id)
|
52
|
+
# # => delete an existing Windoo::Requirement from the Array
|
53
|
+
#
|
54
|
+
# The other CriteriaManagers work the same way, they are just located in their respective places:
|
55
|
+
#
|
56
|
+
# # Patch Capabilities
|
57
|
+
#
|
58
|
+
# patch = title.patches.first
|
59
|
+
# # => a single patch
|
60
|
+
#
|
61
|
+
# patch.capabilities.to_a
|
62
|
+
# # => the readonly Array of Windoo::Capability objects
|
63
|
+
#
|
64
|
+
# patch.capabilities.add_criterion(options: here)
|
65
|
+
# # => add a new Windoo::Capability to the patch
|
66
|
+
#
|
67
|
+
# patch.capabilities.replace_criterion(victim_id, options: here)
|
68
|
+
# # => replace an existing Windoo::Capability in the patch
|
69
|
+
#
|
70
|
+
# patch.capabilities.delete_criterion(victim_id)
|
71
|
+
# # => delete an existing Windoo::Capability from the patch
|
72
|
+
#
|
73
|
+
# # Patch Component Criteria
|
74
|
+
#
|
75
|
+
# component = patch.component
|
76
|
+
# # => the component of a patch
|
77
|
+
#
|
78
|
+
# component.criteria.to_a
|
79
|
+
# # => the readonly Array of Windoo::ComponentCriterion objects
|
80
|
+
#
|
81
|
+
# component.criteria.add_criterion(options: here)
|
82
|
+
# # => add a new Windoo::ComponentCriterion to the component
|
83
|
+
#
|
84
|
+
# component.criteria.replace_criterion(victim_id, options: here)
|
85
|
+
# # => replace an existing Windoo::ComponentCriterion in the component
|
86
|
+
#
|
87
|
+
# component.criteria.delete_criterion(victim_id)
|
88
|
+
# # => delete an existing Windoo::ComponentCriterion from the component
|
89
|
+
#
|
90
|
+
#
|
91
|
+
# Subclasses MUST define the constant MEMBER_CLASS to indicate the class of the items we are managing
|
92
|
+
#
|
93
|
+
class CriteriaManager < Windoo::BaseClasses::ArrayManager
|
94
|
+
|
95
|
+
# Class Methods
|
96
|
+
######################
|
97
|
+
|
98
|
+
# @return [Array<String>] The names of all available recon criteria names
|
99
|
+
#####
|
100
|
+
def self.available_names(cnx: Windoo.cnx)
|
101
|
+
cnx.get 'valuelists/criteria/names'
|
102
|
+
end
|
103
|
+
|
104
|
+
# @return [Array<String>] The possible criteria types
|
105
|
+
#####
|
106
|
+
def self.available_types(cnx: Windoo.cnx)
|
107
|
+
cnx.get 'valuelists/criteria/types'
|
108
|
+
end
|
109
|
+
|
110
|
+
# Find out the available critrion operators for a given criterion.
|
111
|
+
# e.g. for the criterion 'Application Title' the operators are:
|
112
|
+
# ["is", "is not", "has", "does not have"]
|
113
|
+
#
|
114
|
+
# for the criterion 'Application Bundle ID' the operators are:
|
115
|
+
# ["is", "is not", "like", "not like", "matches regex", "does not match regex"]
|
116
|
+
#
|
117
|
+
# for the criterion 'Computer Group' the operators are:
|
118
|
+
# ["member of", "not member of"]
|
119
|
+
#
|
120
|
+
# ...and so on.
|
121
|
+
#
|
122
|
+
# @param name [String] The criterion for which to get the operators
|
123
|
+
#
|
124
|
+
# @return [Array<String>] The possible operators for a given criterion name
|
125
|
+
#
|
126
|
+
#####
|
127
|
+
def self.operators_for(name, cnx: Windoo.cnx)
|
128
|
+
cnx.post 'valuelists/criteria/operators', { name: name }
|
129
|
+
end
|
130
|
+
|
131
|
+
# Public Instance Methods
|
132
|
+
####################################
|
133
|
+
|
134
|
+
# Add a criterion to the end of this array.
|
135
|
+
#
|
136
|
+
# @param name [String] The name of the criterion
|
137
|
+
# To ask the server for an Array of all possible criteria names,
|
138
|
+
# use
|
139
|
+
# Windoo::BaseClasses::CriteriaManager.available_names
|
140
|
+
#
|
141
|
+
# @param operator [String] The operator to use for
|
142
|
+
# comparing the value given here with the value for
|
143
|
+
# a computer.
|
144
|
+
# To ask the server for an Array of all operators available for some
|
145
|
+
# criterion, use
|
146
|
+
# Windoo::BaseClasses::CriteriaManager.operators_for criterion_name
|
147
|
+
#
|
148
|
+
# @param value [String, integer] The value that will be
|
149
|
+
# compared with that on a computer, using the operator.
|
150
|
+
#
|
151
|
+
# @param type [String] how does Jamf Pro get this
|
152
|
+
# value for a computer? 'recon' means its a normal value
|
153
|
+
# gathered by a recon. 'extensionAttribute' means the value
|
154
|
+
# is generated by the extensionAttribute associated with
|
155
|
+
# this SoftwareTitle. Defaults to 'recon'.
|
156
|
+
#
|
157
|
+
# @param and_or [Symbol] :and or :or. Defines how this
|
158
|
+
# criterion is joined with the previous one in a chain of
|
159
|
+
# boolean logic. Default is :and
|
160
|
+
#
|
161
|
+
# @param absoluteOrderId [Integer] The zero-based position of this criterion
|
162
|
+
# among all the others in the array. By default, this criterion will be added
|
163
|
+
# at '-1', the end of the array
|
164
|
+
#
|
165
|
+
# @return [Integer] The id of the new criterion
|
166
|
+
#
|
167
|
+
def add_criterion(name:, operator:, value:, type: 'recon', and_or: :and, absoluteOrderId: nil)
|
168
|
+
absoluteOrderId ||= @managed_array.size
|
169
|
+
|
170
|
+
new_criterion = self.class::MEMBER_CLASS.create(
|
171
|
+
cnx: container.cnx,
|
172
|
+
container: container,
|
173
|
+
and_or: and_or,
|
174
|
+
name: name,
|
175
|
+
operator: operator,
|
176
|
+
value: value,
|
177
|
+
type: type.to_s,
|
178
|
+
absoluteOrderId: absoluteOrderId
|
179
|
+
)
|
180
|
+
|
181
|
+
# call the method from our superclass to add it to the array
|
182
|
+
add_member new_criterion, index: absoluteOrderId
|
183
|
+
update_local_absoluteOrderIds
|
184
|
+
new_criterion.primary_id
|
185
|
+
end
|
186
|
+
|
187
|
+
# Create a new criterion from the provided attributes and use it
|
188
|
+
# to replace the one with the given id.
|
189
|
+
#
|
190
|
+
# @param id [Integer] The primary ID of the criterion to update.
|
191
|
+
# So for an array of Windoo::Requirement, you would provide a 'requirementId'
|
192
|
+
#
|
193
|
+
# @param name [String] The name of the criterion
|
194
|
+
# To get an Array of all possible criteria names, use
|
195
|
+
# Windoo::BaseClasses::CriteriaManager.available_names
|
196
|
+
#
|
197
|
+
# @param operator [String] The operator to use for
|
198
|
+
# comparing the value given here with the value for
|
199
|
+
# a computer.
|
200
|
+
# To get an Array of all operators available for some criterion,
|
201
|
+
# use Windoo::BaseClasses::CriteriaManager.operators_for criterion_name
|
202
|
+
#
|
203
|
+
# @param value [String, integer] The value that will be
|
204
|
+
# compared with that on a computer, using the operator.
|
205
|
+
#
|
206
|
+
# @param type [String] how does Jamf Pro get this
|
207
|
+
# value for a computer? 'recon' means its a normal value
|
208
|
+
# gathered by a recon. 'extensionAttribute' means the value
|
209
|
+
# is generated by the extensionAttribute associated with
|
210
|
+
# this SoftwareTitle. Defaults to 'recon'.
|
211
|
+
#
|
212
|
+
# @param and_or [Symbol] :and or :or. Defines how this
|
213
|
+
# criterion is joined with the previous one in a chain of
|
214
|
+
# boolean logic. Default is :and
|
215
|
+
#
|
216
|
+
# @return [Integer] The id of the new criterion
|
217
|
+
#
|
218
|
+
def replace_criterion(id, name:, operator:, value:, type: 'recon', and_or: :and)
|
219
|
+
victim = delete_member(id)
|
220
|
+
|
221
|
+
add_criterion(
|
222
|
+
and_or: and_or,
|
223
|
+
name: name,
|
224
|
+
operator: operator,
|
225
|
+
value: value,
|
226
|
+
type: type.to_s,
|
227
|
+
absoluteOrderId: victim.absoluteOrderId
|
228
|
+
)
|
229
|
+
# no need to run update_local_absoluteOrderIds, we haven't changed the order,
|
230
|
+
# and it was called by add_criterion
|
231
|
+
|
232
|
+
# Windoo::ConnectionError should only come from the Add operation,
|
233
|
+
# usually when one of the attributes given was a problem.
|
234
|
+
#
|
235
|
+
# The delete should give a Windoo::NoSuchItemError if the id doesn't
|
236
|
+
# exist on the server.
|
237
|
+
rescue Windoo::ConnectionError
|
238
|
+
# make sure the victim was really removed from the array
|
239
|
+
# It should have been by the delete_member call above,
|
240
|
+
@managed_array.delete_if { |c| c.primary_id == victim.primary_id }
|
241
|
+
|
242
|
+
# then re-add the victim in the same position
|
243
|
+
add_criterion(
|
244
|
+
and_or: victim.and_or,
|
245
|
+
name: victim.name,
|
246
|
+
operator: victim.operator,
|
247
|
+
value: victim.value,
|
248
|
+
type: victim.type.to_s,
|
249
|
+
absoluteOrderId: victim.absoluteOrderId
|
250
|
+
)
|
251
|
+
# and re-raise the error
|
252
|
+
raise
|
253
|
+
end
|
254
|
+
|
255
|
+
# Change the position of an existing criterion in the array
|
256
|
+
#
|
257
|
+
# @param id [Integer] The primary ID of the criterion to update.
|
258
|
+
# So for an array of Windoo::Requirement, you would provide a 'requirementId'
|
259
|
+
#
|
260
|
+
# @param absoluteOrderId [Integer] The zero-based position to which you want to
|
261
|
+
# move the criterion. So if you want to make it the third criterion
|
262
|
+
# in the list, use 2.
|
263
|
+
#
|
264
|
+
# @return [Integer] the new absoluteOrderId
|
265
|
+
#
|
266
|
+
def move_criterion(id, absoluteOrderId:)
|
267
|
+
# Can't move it beyond the end of the array....
|
268
|
+
max_idx = @managed_array.size - 1
|
269
|
+
absoluteOrderId = max_idx if absoluteOrderId > max_idx
|
270
|
+
|
271
|
+
# ... or before the beginning
|
272
|
+
absoluteOrderId = 0 if absoluteOrderId.negative?
|
273
|
+
|
274
|
+
# do it on the server first, to raise potential errs before
|
275
|
+
# modifying the array
|
276
|
+
criterion = update_member id, absoluteOrderId: absoluteOrderId
|
277
|
+
|
278
|
+
# now modify the array
|
279
|
+
move_member criterion, index: absoluteOrderId
|
280
|
+
update_local_absoluteOrderIds
|
281
|
+
|
282
|
+
absoluteOrderId
|
283
|
+
end
|
284
|
+
|
285
|
+
# Delete a criterion by its id
|
286
|
+
#
|
287
|
+
# @param id [Integer] The primary ID of the criterion to delete.
|
288
|
+
# So for an array of Windoo::Requirement, you would provide a 'requirementId'
|
289
|
+
#
|
290
|
+
# @return [Integer] The id of the deleted criterion
|
291
|
+
#
|
292
|
+
def delete_criterion(id)
|
293
|
+
delid = delete_member(id).deleted_id
|
294
|
+
update_local_absoluteOrderIds
|
295
|
+
delid
|
296
|
+
end
|
297
|
+
|
298
|
+
# Delete all the criteria
|
299
|
+
#
|
300
|
+
# @return [void]
|
301
|
+
#
|
302
|
+
def delete_all_criteria
|
303
|
+
delete_all_members
|
304
|
+
end
|
305
|
+
|
306
|
+
# Private Instance Methods
|
307
|
+
####################################
|
308
|
+
private
|
309
|
+
|
310
|
+
# Update the local absoluteOrderId of Array members
|
311
|
+
# to match their array index, without updating the server
|
312
|
+
# cuz the server should have done it automatically
|
313
|
+
#
|
314
|
+
# @return [void]
|
315
|
+
def update_local_absoluteOrderIds
|
316
|
+
@managed_array.each_with_index do |criterion, index|
|
317
|
+
next unless criterion
|
318
|
+
|
319
|
+
criterion.local_absoluteOrderId = index
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
end # class Criterion
|
324
|
+
|
325
|
+
end # module BaseClasses
|
326
|
+
|
327
|
+
end # module Windoo
|