ruby-jss 1.4.1 → 1.5.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.

Potentially problematic release.


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

Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +38 -0
  3. data/lib/jamf.rb +10 -3
  4. data/lib/jamf/api/abstract_classes/collection_resource.rb +329 -150
  5. data/lib/jamf/api/abstract_classes/generic_reference.rb +9 -1
  6. data/lib/jamf/api/abstract_classes/json_object.rb +106 -82
  7. data/lib/jamf/api/abstract_classes/prestage.rb +54 -29
  8. data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +21 -0
  9. data/lib/jamf/api/abstract_classes/resource.rb +4 -4
  10. data/lib/jamf/api/abstract_classes/singleton_resource.rb +1 -1
  11. data/lib/jamf/api/connection.rb +13 -9
  12. data/lib/jamf/api/connection/api_error.rb +8 -8
  13. data/lib/jamf/api/connection/token.rb +16 -15
  14. data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +14 -1
  15. data/lib/jamf/api/json_objects/device_enrollment_device.rb +14 -7
  16. data/lib/jamf/api/json_objects/device_enrollment_device_sync_state.rb +81 -0
  17. data/lib/jamf/api/json_objects/locale.rb +59 -0
  18. data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +50 -1
  19. data/lib/jamf/api/json_objects/prestage_location.rb +3 -3
  20. data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +7 -7
  21. data/lib/jamf/api/json_objects/prestage_scope.rb +1 -1
  22. data/lib/jamf/api/{resources/collection_resources → json_objects}/time_zone.rb +9 -23
  23. data/lib/jamf/api/mixins/bulk_deletable.rb +27 -6
  24. data/lib/jamf/api/mixins/change_log.rb +201 -51
  25. data/lib/jamf/api/mixins/filterable.rb +51 -0
  26. data/lib/jamf/api/mixins/pageable.rb +208 -0
  27. data/lib/jamf/api/mixins/sortable.rb +59 -0
  28. data/lib/jamf/api/resources/collection_resources/building.rb +19 -8
  29. data/lib/jamf/api/resources/collection_resources/category.rb +5 -3
  30. data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +11 -4
  31. data/lib/jamf/api/resources/collection_resources/device_enrollment.rb +10 -10
  32. data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +11 -3
  33. data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +24 -22
  34. data/lib/jamf/api/resources/collection_resources/script.rb +61 -25
  35. data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +15 -5
  36. data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +14 -14
  37. data/lib/jamf/api/resources/singleton_resources/locales.rb +155 -0
  38. data/lib/jamf/api/resources/singleton_resources/time_zones.rb +213 -0
  39. data/lib/jamf/validate.rb +63 -24
  40. data/lib/jamf/version.rb +1 -1
  41. data/lib/jss.rb +2 -1
  42. data/lib/jss/api_connection.rb +110 -370
  43. data/lib/jss/api_object.rb +3 -19
  44. data/lib/jss/api_object/categorizable.rb +1 -1
  45. data/lib/jss/api_object/configuration_profile.rb +34 -3
  46. data/lib/jss/api_object/directory_binding_type.rb +66 -60
  47. data/lib/jss/api_object/directory_binding_type/active_directory.rb +71 -34
  48. data/lib/jss/api_object/directory_binding_type/admitmac.rb +536 -467
  49. data/lib/jss/api_object/directory_binding_type/centrify.rb +21 -7
  50. data/lib/jss/api_object/directory_binding_type/open_directory.rb +4 -4
  51. data/lib/jss/api_object/distribution_point.rb +2 -2
  52. data/lib/jss/api_object/dock_item.rb +102 -96
  53. data/lib/jss/api_object/extendable.rb +1 -1
  54. data/lib/jss/api_object/group.rb +33 -2
  55. data/lib/jss/api_object/network_segment.rb +43 -12
  56. data/lib/jss/api_object/patch_source.rb +10 -9
  57. data/lib/jss/api_object/printer.rb +10 -4
  58. data/lib/jss/api_object/scopable.rb +10 -15
  59. data/lib/jss/exceptions.rb +3 -0
  60. data/lib/jss/server.rb +15 -0
  61. data/lib/jss/version.rb +1 -1
  62. metadata +37 -22
@@ -25,6 +25,14 @@
25
25
 
26
26
  module Jamf
27
27
 
28
+ # TODO: This class and the referable mixin should be removed -
29
+ # According to the Jamf Pro API Styleguide/Specs:
30
+ #
31
+ # - Objects which reference other objects MUST only reference by its Jamf Pro-assigned numerical ID.
32
+ #
33
+ # and in newer endpoints that is what we're seeing, e.g. fields like
34
+ # 'siteId' and 'categoryId'
35
+
28
36
  # This class is a reference to an individual API object from some other
29
37
  # API object.
30
38
  #
@@ -53,7 +61,7 @@ module Jamf
53
61
  OBJECT_MODEL = {
54
62
 
55
63
  id: {
56
- class: :integer,
64
+ class: :j_id,
57
65
  identifier: :primary,
58
66
  readonly: true
59
67
  },
@@ -179,6 +179,7 @@ module Jamf
179
179
  # - enum:
180
180
  # - validator:
181
181
  # - aliases:
182
+ # - filter_key:
182
183
  #
183
184
  # For an example of an OBJECT_MODEL hash, see {Jamf::MobileDeviceDetails::OBJECT_MODEL}
184
185
  #
@@ -189,15 +190,27 @@ module Jamf
189
190
  # -----------------
190
191
  # This is the only required key for all attributes.
191
192
  #
192
- # Symbol is one of :string, :integer, :float, or :boolean
193
- # These are the JSON data types that don't need parsing into ruby
193
+ # ---
194
+ # Symbol is one of :string, :integer, :float, :boolean, or :j_id
195
+ #
196
+ # The first four are the JSON data types that don't need parsing into ruby
194
197
  # beyond that done by `JSON.parse`. When processing an attribute with one of
195
198
  # these symbols as the `class:`, the JSON value is used as-is.
196
199
  #
197
- # When this is not a Symbol, it must be an actual class, such as
200
+ # The ':j_id' symbol means this value is an id used to reference an object in
201
+ # a collection resource of the API - all such objects have an 'id' attribute
202
+ # which is a String containing an Integer.
203
+ #
204
+ # These ids are used not only as the id attribute of the object itself, but
205
+ # if an object contains references to one or more other objects, those
206
+ # references are also ':j_id' values.
207
+ # In setters and .create, :j_id values can take either an integer or an
208
+ # integer-in-a-string, and are stored as integer-in-a-string/
209
+ #
210
+ # When 'class:' is not a Symbol, it must be an actual class, such as
198
211
  # Jamf::Timestamp or Jamf::PurchasingData.
199
212
  #
200
- # Classes used this way _must_:
213
+ # Actual classes used this way _must_:
201
214
  #
202
215
  # - Have an #initialize method that takes two parameters and performs
203
216
  # validation on them:
@@ -280,10 +293,11 @@ module Jamf
280
293
  # 2. so that validation can be performed on values added to the array.
281
294
  #
282
295
  #
283
- # enum: \[Constant -> Array<Constants> ]
296
+ # enum: \[Constant -> Array ]
284
297
  # -----------------
285
298
  # This is a constant defined somewhere in the Jamf module. The constant
286
- # must contain an Array of other Constant values, usually Strings.
299
+ # must contain an Array of values, usually Strings. You may or may not choose
300
+ # to define the array members as constants themselves.
287
301
  #
288
302
  # Example:
289
303
  # > Attribute `:type` has enum: Jamf::ExtentionAttribute::DATA_TYPES
@@ -305,9 +319,10 @@ module Jamf
305
319
  # >
306
320
  #
307
321
  # Setters for attributes with an enum require that the new value is
308
- # a member of the array as seen above. When using such setters, its wise to
309
- # use the array members themselves rather than a different but identical string,
310
- # however either will work. In other words, this:
322
+ # a member of the array as seen above. When using such setters, If you defined
323
+ # the array members as constants themselves, it is wise to use those rather
324
+ # than a different but identical string, however either will work.
325
+ # In other words, this:
311
326
  #
312
327
  # my_ea.dataType = Jamf::ExtentionAttribute::DATA_TYPE_INTEGER
313
328
  #
@@ -356,6 +371,14 @@ module Jamf
356
371
  #
357
372
  # Attributes of class :boolean automatically have a getter alias ending with a '?'.
358
373
  #
374
+ # filter_key: \[Boolean]
375
+ # -----------------
376
+ # For subclasses of CollectionResource, GETting the main endpoint will return
377
+ # the entire collection. Some of these endpoints support RSQL filters to return
378
+ # only those objects that match the filter. If this attribute can be used as
379
+ # a field for filtering, set filter_key: to true, and filters will be used
380
+ # where possible to optimize GET requests.
381
+ #
359
382
  # Documenting your code
360
383
  # ---------------------
361
384
  # For documenting attributes with YARD, put this above each
@@ -401,22 +424,35 @@ module Jamf
401
424
  # attribute as described above. Validation failure will raise an exception,
402
425
  # usually Jamf::InvalidDataError.
403
426
  #
404
- # If the attribute is defined with an enum, the value must be
405
- # a key or value of the enum.
427
+ # Only one value-validation is applied, depending on the attribute definition:
428
+ #
429
+ # - If the attribute is defined with a specific validator, the value is passed
430
+ # to that validator, and other validators are ignored
431
+ #
432
+ # - If the attribute is defined with an enum, the value must be
433
+ # a value of the enum.
434
+ #
435
+ # - If the attribute is defined as a :string, :integer, :float or :bool
436
+ # without an enum or validator, it is confirmed to be the correct type
437
+ #
438
+ # - If the attribute is defined to hold a :j_id, the Validate.j_id method
439
+ # is used, it must be an integer or integer-in-string
440
+ #
441
+ # - If the attribute is defined to hold a JAMF class, (e.g. Jamf::Timestamp)
442
+ # the class itself performs validation on the value when instantiated
443
+ # with the value.
406
444
  #
407
- # If the attribute's class: is defined as a Class, (e.g. Jamf::Timestamp)
408
- # its .new method is called with the value and the current API connection.
409
- # The class itself performs valuation when the value is used to
410
- # instantiate it.
445
+ # - Otherwise, the value is used unchanged with no validation
411
446
  #
412
- # If the attribute is defined with a validator, the value is passed
413
- # to that validator.
447
+ # Additionally:
414
448
  #
415
- # If the attribute is defined as a :string, :integer, :float or :bool
416
- # without an enum or validator, it is checked to be the correct type
449
+ # - If an attribute is an identifier, it must be unique in its class and
450
+ # API connection.
417
451
  #
418
- # If an attribute is an identifier, it must be unique in its class and
419
- # API connection.
452
+ # - If an attribute is required, it may not be nil or empty
453
+ #
454
+ # - If an attribute is :multi, the value must be an array and each member
455
+ # value is validated individually
420
456
  #
421
457
  # ### Constructor / Instantiation {#constructor}
422
458
  #
@@ -478,12 +514,6 @@ module Jamf
478
514
  # These classes are used from JSON in the raw
479
515
  JSON_TYPE_CLASSES = %i[string integer float boolean].freeze
480
516
 
481
- # Predicate (boolean) attibutes that start with this RE will
482
- # have an alias without the 'is' so :isManaged will have
483
- # getters isManaged? and managed?
484
- #
485
- PREDICATE_RE = /^is([A-Z]\w+)$/.freeze
486
-
487
517
  # Public Class Methods
488
518
  #####################################
489
519
 
@@ -542,7 +572,9 @@ module Jamf
542
572
  need_list_methods = ancestors.include?(Jamf::CollectionResource)
543
573
 
544
574
  self::OBJECT_MODEL.each do |attr_name, attr_def|
545
- create_list_methods(attr_name, attr_def) if need_list_methods && attr_def[:identifier]
575
+
576
+ # don't make one for :id, that one's hard-coded into CollectionResource
577
+ create_list_methods(attr_name, attr_def) if need_list_methods && attr_def[:identifier] && attr_name != :id
546
578
 
547
579
  # there can be only one (primary ident)
548
580
  if attr_def[:identifier] == :primary
@@ -591,9 +623,6 @@ module Jamf
591
623
  ##############################
592
624
  def self.define_predicates(attr_name)
593
625
  alias_method("#{attr_name}?", attr_name)
594
- return unless attr_name.to_s =~ PREDICATE_RE
595
-
596
- alias_method("#{Regexp.last_match(1).downcase}?", attr_name)
597
626
  end
598
627
 
599
628
  # create setter(s) for an attribute, and any aliases needed
@@ -610,6 +639,7 @@ module Jamf
610
639
  new_value = validate_attr attr_name, new_value
611
640
  old_value = instance_variable_get("@#{attr_name}")
612
641
  return if new_value == old_value
642
+
613
643
  instance_variable_set("@#{attr_name}", new_value)
614
644
  note_unsaved_change attr_name, old_value
615
645
  end # define method
@@ -638,9 +668,11 @@ module Jamf
638
668
  define_method("#{attr_name}=") do |new_value|
639
669
  instance_variable_set("@#{attr_name}", []) unless instance_variable_get("@#{attr_name}").is_a?(Array)
640
670
  raise Jamf::InvalidDataError, 'Value must be an Array' unless new_value.is_a? Array
671
+
641
672
  new_value.map! { |item| validate_attr attr_name, item }
642
673
  old_value = instance_variable_get("@#{attr_name}")
643
674
  return if new_value == old_value
675
+
644
676
  instance_variable_set("@#{attr_name}", new_value)
645
677
  note_unsaved_change attr_name, old_value
646
678
  end # define method
@@ -752,26 +784,6 @@ module Jamf
752
784
  #
753
785
  # returns a valid value or raises an exception
754
786
  #
755
- # If the attribute is defined to hold a JAMF class, (e.g. Jamf::Timestamp)
756
- # the class itself performs validation on the value when instantiated
757
- # with the value.
758
- #
759
- # If the attribute is defined with an enum, the value must be
760
- # a key of the enum.
761
- #
762
- # If the attribute is defined with a validator, the value is passed
763
- # to that validator.
764
- #
765
- # If the attribute is defined as a :string, :integer, :float or :bool
766
- # without an enum or validator, it is confirmed to be the correct type
767
- #
768
- # If the attribute is required, it can't be nil or empty
769
- #
770
- # If the attribute is an identifier, and the class is a subclass of
771
- # CollectionResource, it must be unique among the collection
772
- #
773
- # Otherwise, the value is returned unchanged.
774
- #
775
787
  # This method only validates single values. When called from multi-value
776
788
  # setters, it is used for each value individually.
777
789
  #
@@ -783,36 +795,11 @@ module Jamf
783
795
  #
784
796
  def self.validate_attr(attr_name, value, cnx: Jamf.cnx)
785
797
  attr_def = self::OBJECT_MODEL[attr_name]
786
-
787
798
  raise ArgumentError, "Unknown attribute: #{attr_name} for #{self} objects" unless attr_def
788
799
 
789
800
  # validate our value, which will raise an error or
790
801
  # convert the value to the required type.
791
- value =
792
-
793
- # by enum, must be a value of the enum
794
- if attr_def[:enum]
795
- return value if attr_def[:enum].include? value
796
- raise Jamf::InvalidDataError, "Value must be one of: :#{attr_def[:enum].join ', :'}"
797
-
798
- # by class, the class validates the value passed with .new
799
- elsif attr_def[:class].is_a? Class
800
- klass = attr_def[:class]
801
- # validation happens in klass.new
802
- value.is_a?(klass) ? value : klass.new(value, cnx: cnx)
803
-
804
- # by specified Validate method - pass to the method
805
- elsif attr_def[:validator]
806
- Jamf::Validate.send(attr_def[:validator], value)
807
-
808
- # By json primative type - pass to the matching validate method
809
- elsif JSON_TYPE_CLASSES.include? attr_def[:class]
810
- Jamf::Validate.send(attr_def[:class], value)
811
-
812
- # raw, no validation, should be rare
813
- else
814
- value
815
- end # if
802
+ value = validate_attr_value(attr_def, value, cnx: Jamf.cnx)
816
803
 
817
804
  # if this is required, it can't be nil or empty
818
805
  if attr_def[:required]
@@ -826,6 +813,41 @@ module Jamf
826
813
  end # validate_attr(attr_name, value)
827
814
  private_class_method :validate_attr
828
815
 
816
+ # Validate an attribute value itself, as part of validating the attribute
817
+ # as a whole. Only one validation is applied, which one is
818
+ # determined in the order described in the #### Data Validation section
819
+ # of the JSONObject class comments
820
+ #
821
+ # See .validate_attr, which calls this
822
+ def self.validate_attr_value(attr_def, value, cnx: Jamf.cnx)
823
+ # by specified Validate method
824
+ if attr_def[:validator]
825
+ Jamf::Validate.send attr_def[:validator], value
826
+
827
+ # by enum, must be a value of the enum
828
+ elsif attr_def[:enum]
829
+ Jamf::Validate.in_enum(value, attr_def[:enum])
830
+
831
+ # By json primative type - pass to the matching validate method
832
+ elsif JSON_TYPE_CLASSES.include? attr_def[:class]
833
+ Jamf::Validate.send attr_def[:class], value
834
+
835
+ # a JPAPI id?
836
+ elsif attr_def[:class] == :j_id
837
+ Jamf::Validate.j_id value
838
+
839
+ # by Class, the class validates the value passed with .new
840
+ elsif attr_def[:class].is_a? Class
841
+ klass = attr_def[:class]
842
+ value.is_a?(klass) ? value : klass.new(value, cnx: cnx)
843
+
844
+ # raw, no validation, should be rare
845
+ else
846
+ value
847
+ end # if
848
+ end
849
+ private_class_method :validate_attr_value
850
+
829
851
  # Attributes
830
852
  #####################################
831
853
 
@@ -1046,6 +1068,10 @@ module Jamf
1046
1068
  elsif attr_def[:class].class == Class
1047
1069
  attr_def[:class].new api_value, cnx: @cnx
1048
1070
 
1071
+ # a :j_id value. See the docs for OBJECT_MODEL in Jamf::JSONObject
1072
+ elsif attr_def[:class] == :j_id
1073
+ api_value.to_s
1074
+
1049
1075
  # a JSON value
1050
1076
  else
1051
1077
  api_value
@@ -1058,11 +1084,9 @@ module Jamf
1058
1084
  # @return (see parse_single_init_value)
1059
1085
  #
1060
1086
  def parse_enum_value(api_value, attr_name, attr_def)
1061
- if attr_def[:enum].include? api_value
1062
- api_value
1063
- else
1064
- raise Jamf::InvalidDataError, "#{api_value} is not in the enum for attribute #{attr_name}"
1065
- end
1087
+ raise Jamf::InvalidDataError, "#{api_value} is not in the enum for attribute #{attr_name}" unless attr_def[:enum].include? api_value
1088
+
1089
+ api_value
1066
1090
  end
1067
1091
 
1068
1092
  # call to_jamf on a single value
@@ -29,14 +29,11 @@ module Jamf
29
29
  # Classes
30
30
  #####################################
31
31
 
32
- # A building defined in the JSS
32
+ # The parent class of ComputerPrestage, and MobileDevicePrestage
33
+ # holding common code.
33
34
  class Prestage < Jamf::CollectionResource
34
35
 
35
36
  extend Jamf::Abstract
36
-
37
- # for now, subclasses are not creatable
38
- extend Jamf::UnCreatable
39
-
40
37
  include Jamf::Lockable
41
38
 
42
39
  # Constants
@@ -49,9 +46,9 @@ module Jamf
49
46
  OBJECT_MODEL = {
50
47
 
51
48
  # @!attribute [r] id
52
- # @return [Integer]
49
+ # @return [String]
53
50
  id: {
54
- class: :integer,
51
+ class: :j_id,
55
52
  identifier: :primary,
56
53
  readonly: true
57
54
  },
@@ -66,15 +63,15 @@ module Jamf
66
63
  aliases: %i[name]
67
64
  },
68
65
 
69
- # @!attribute isMandatory
66
+ # @!attribute mandatory
70
67
  # @return [Boolean]
71
- isMandatory: {
68
+ mandatory: {
72
69
  class: :boolean
73
70
  },
74
71
 
75
- # @!attribute isMdmRemovable
72
+ # @!attribute mdmRemovable
76
73
  # @return [Boolean]
77
- isMdmRemovable: {
74
+ mdmRemovable: {
78
75
  class: :boolean
79
76
  },
80
77
 
@@ -96,9 +93,9 @@ module Jamf
96
93
  class: :string
97
94
  },
98
95
 
99
- # @!attribute isDefaultPrestage
96
+ # @!attribute defaultPrestage
100
97
  # @return [Boolean]
101
- isDefaultPrestage: {
98
+ defaultPrestage: {
102
99
  class: :boolean,
103
100
  aliases: [:default?]
104
101
  },
@@ -106,24 +103,24 @@ module Jamf
106
103
  # @!attribute enrollmentSiteId
107
104
  # @return [Integer]
108
105
  enrollmentSiteId: {
109
- class: :integer
106
+ class: :j_id
110
107
  },
111
108
 
112
- # @!attribute isKeepExistingSiteMembership
109
+ # @!attribute keepExistingSiteMembership
113
110
  # @return [Boolean]
114
- isKeepExistingSiteMembership: {
111
+ keepExistingSiteMembership: {
115
112
  class: :boolean
116
113
  },
117
114
 
118
- # @!attribute isKeepExistingLocationInformation
115
+ # @!attribute keepExistingLocationInformation
119
116
  # @return [Boolean]
120
- isKeepExistingLocationInformation: {
117
+ keepExistingLocationInformation: {
121
118
  class: :boolean
122
119
  },
123
120
 
124
- # @!attribute isRequireAuthentication
121
+ # @!attribute requireAuthentication
125
122
  # @return [Boolean]
126
- isRequireAuthentication: {
123
+ requireAuthentication: {
127
124
  class: :boolean
128
125
  },
129
126
 
@@ -133,16 +130,22 @@ module Jamf
133
130
  class: :string
134
131
  },
135
132
 
136
- # @!attribute isEnableDeviceBasedActivationLock
133
+ # @!attribute preventActivationLock
137
134
  # @return [Boolean]
138
- isEnableDeviceBasedActivationLock: {
135
+ preventActivationLock: {
136
+ class: :boolean
137
+ },
138
+
139
+ # @!attribute enableDeviceBasedActivationLock
140
+ # @return [Boolean]
141
+ enableDeviceBasedActivationLock: {
139
142
  class: :boolean
140
143
  },
141
144
 
142
145
  # @!attribute deviceEnrollmentProgramInstanceId
143
146
  # @return [Integer]
144
147
  deviceEnrollmentProgramInstanceId: {
145
- class: :integer
148
+ class: :j_id
146
149
  },
147
150
 
148
151
  # @!attribute locationInformation
@@ -169,19 +172,37 @@ module Jamf
169
172
  # @!attribute enrollmentCustomizationId
170
173
  # @return [Integer]
171
174
  enrollmentCustomizationId: {
172
- class: :integer
175
+ class: :j_id
176
+ },
177
+
178
+ # @!attribute language
179
+ # @return [String]
180
+ language: {
181
+ class: :string
182
+ },
183
+
184
+ # @!attribute region
185
+ # @return [String]
186
+ region: {
187
+ class: :string
188
+ },
189
+
190
+ # @!attribute autoAdvanceSetup
191
+ # @return [Boolean]
192
+ autoAdvanceSetup: {
193
+ class: :boolean
173
194
  },
174
195
 
175
196
  # @!attribute profileUUID
176
197
  # @return [String]
177
- profileUUID: {
198
+ profileUuid: {
178
199
  class: :string
179
200
  },
180
201
 
181
202
  # @!attribute siteId
182
203
  # @return [Integer]
183
204
  siteId: {
184
- class: :integer
205
+ class: :j_id
185
206
  }
186
207
 
187
208
  }.freeze
@@ -201,10 +222,14 @@ module Jamf
201
222
  # @return [Jamf::Prestage, nil]
202
223
  #
203
224
  def self.default
204
- id = all.select { |ps| ps[:isDefaultPrestage] }.first.dig :id
205
- return nil unless id
225
+ # only one can be true at a time, so sort desc by that field,
226
+ # and the true one will be at the top
227
+ default_prestage_data = all(sort: 'defaultPrestage:desc', paged: true, page_size: 1).first
228
+
229
+ # Just in case there was no true one, make sure defaultPrestage is true
230
+ return unless default_prestage_data&.dig(:defaultPrestage)
206
231
 
207
- fetch id: id
232
+ fetch id: default_prestage_data[:id]
208
233
  end
209
234
 
210
235
  # Return all scoped serial numbers and the id of the prestage