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
@@ -45,7 +45,7 @@ module Jamf
45
45
 
46
46
  # @!attribute isUsed [r]
47
47
  # @return [Boolean]
48
- isUsed: {
48
+ used: {
49
49
  class: :boolean
50
50
  }
51
51
  }.freeze
@@ -64,13 +64,13 @@ module Jamf
64
64
 
65
65
  # @!attribute isManageNames
66
66
  # @return [Boolean]
67
- isManageNames: {
67
+ manageNames: {
68
68
  class: :boolean
69
69
  },
70
70
 
71
71
  # @!attribute isDeviceNamingConfigured
72
72
  # @return [Boolean]
73
- isDeviceNamingConfigured: {
73
+ deviceNamingConfigured: {
74
74
  class: :boolean
75
75
  }
76
76
  }.freeze
@@ -26,7 +26,34 @@
26
26
  # The module
27
27
  module Jamf
28
28
 
29
- # A 'location' for a computer prestage in Jamf Pro
29
+ # The 'skip Setup Items' for a mobile device prestage in Jamf Pro
30
+ # The ones in common with computers are in the superclass
31
+ # To see the ones that should be here, remove anything that's in
32
+ # computers's list from the device ones, thus:
33
+ #
34
+ # (Jamf::MobileDevicePrestage.all.sample[:skipSetupItems].keys - Jamf::ComputerPrestage.all.sample[:skipSetupItems].keys).sort
35
+ # => [:Android,
36
+ # :CloudStorage,
37
+ # :ExpressLanguage,
38
+ # :HomeButtonSensitivity,
39
+ # :OnBoarding,
40
+ # :Passcode,
41
+ # :PreferredLanguage,
42
+ # :RestoreCompleted,
43
+ # :SIMSetup,
44
+ # :ScreenSaver,
45
+ # :SoftwareUpdate,
46
+ # :TVHomeScreenSync,
47
+ # :TVProviderSignIn,
48
+ # :TVRoom,
49
+ # :TapToSetup,
50
+ # :TransferData,
51
+ # :UpdateCompleted,
52
+ # :WatchMigration,
53
+ # :Welcome,
54
+ # :Zoom,
55
+ # :iMessageAndFaceTime]
56
+ #
30
57
  class MobileDevicePrestageSkipSetupItems < Jamf::PrestageSkipSetupItems
31
58
 
32
59
  OBJECT_MODEL = superclass::OBJECT_MODEL.merge(
@@ -87,6 +114,14 @@ module Jamf
87
114
  aliases: %i[preferredLanguage preferredlanguage preferred_language]
88
115
  },
89
116
 
117
+ # @!attribute RestoreCompleted
118
+ # @return [Boolean]
119
+ RestoreCompleted: {
120
+ class: :boolean,
121
+ aliases: %i[restorecompleted restoreCompleted restore_completed]
122
+ },
123
+
124
+
90
125
  # @!attribute SIMSetup
91
126
  # @return [Boolean]
92
127
  SIMSetup: {
@@ -136,6 +171,20 @@ module Jamf
136
171
  aliases: %i[tapToSetup taptosetup tap_to_setup]
137
172
  },
138
173
 
174
+ # @!attribute TransferData
175
+ # @return [Boolean]
176
+ TransferData: {
177
+ class: :boolean,
178
+ aliases: %i[transferData transferdata transfer_data]
179
+ },
180
+
181
+ # @!attribute UpdateCompleted
182
+ # @return [Boolean]
183
+ UpdateCompleted: {
184
+ class: :boolean,
185
+ aliases: %i[updateCompleted updatecompleted update_completed]
186
+ },
187
+
139
188
  # @!attribute WatchMigration
140
189
  # @return [Boolean]
141
190
  WatchMigration: {
@@ -42,8 +42,8 @@ module Jamf
42
42
 
43
43
  # @!attribute assignmentEpoch
44
44
  # @return [Integer]
45
- assignmentEpoch: {
46
- class: :integer
45
+ assignmentDate: {
46
+ class: Jamf::Timestamp
47
47
  },
48
48
 
49
49
  # @!attribute userAssigned
@@ -36,7 +36,7 @@ module Jamf
36
36
  # @!attribute id
37
37
  # @return [Integer]
38
38
  id: {
39
- class: :integer,
39
+ class: :j_id,
40
40
  identifier: :primary
41
41
  },
42
42
 
@@ -79,14 +79,14 @@ module Jamf
79
79
  # @param [integer]
80
80
  # @return [integer]
81
81
  departmentId: {
82
- class: :integer
82
+ class: :j_id
83
83
  },
84
84
 
85
85
  # @!attribute building
86
86
  # @param [integer]
87
87
  # @return [integer]
88
88
  buildingId: {
89
- class: :integer
89
+ class: :j_id
90
90
  },
91
91
 
92
92
  # @!attribute room
@@ -36,28 +36,28 @@ module Jamf
36
36
  # @!attribute id
37
37
  # @return [Integer]
38
38
  id: {
39
- class: :integer,
39
+ class: :j_id,
40
40
  identifier: :primary
41
41
  },
42
42
 
43
- # @!attribute isPurchased
43
+ # @!attribute purchased
44
44
  # @param [Boolean]
45
45
  # @return [Boolean]
46
- isPurchased: {
46
+ purchased: {
47
47
  class: :boolean
48
48
  },
49
49
 
50
- # @!attribute isLeased
50
+ # @!attribute leased
51
51
  # @param [Boolean]
52
52
  # @return [Boolean]
53
- isLeased: {
53
+ leased: {
54
54
  class: :boolean
55
55
  },
56
56
 
57
- # @!attribute appleCareID
57
+ # @!attribute appleCareId
58
58
  # @param [String]
59
59
  # @return [String]
60
- appleCareID: {
60
+ appleCareId: {
61
61
  class: :string
62
62
  },
63
63
 
@@ -39,7 +39,7 @@ module Jamf
39
39
  # @!attribute prestageId
40
40
  # @return [Integer]
41
41
  prestageId: {
42
- class: :integer
42
+ class: :j_id
43
43
  },
44
44
 
45
45
  # @!attribute assignments
@@ -23,28 +23,11 @@
23
23
  #
24
24
  #
25
25
 
26
- # The Module
26
+ # The module
27
27
  module Jamf
28
28
 
29
- # Classes
30
- #####################################
31
-
32
- # A building defined in the JSS
33
- class TimeZone < Jamf::CollectionResource
34
-
35
- # Mix-Ins
36
- #####################################
37
-
38
- extend Jamf::Immutable
39
- extend Jamf::UnCreatable
40
- extend Jamf::UnDeletable
41
-
42
- # Constants
43
- #####################################
44
-
45
- RSRC_VERSION = 'v1'.freeze
46
-
47
- RSRC_PATH = 'time-zones'.freeze
29
+ # A Time Zone known to Jamf Pro
30
+ class TimeZone < Jamf::JSONObject
48
31
 
49
32
  # Object Model / Attributes
50
33
  # See APIObject class documentation for details
@@ -57,6 +40,7 @@ module Jamf
57
40
  zoneId: {
58
41
  class: :string,
59
42
  identifier: :primary,
43
+ read_only: true,
60
44
  aliases: [:id]
61
45
  },
62
46
 
@@ -65,13 +49,15 @@ module Jamf
65
49
  displayName: {
66
50
  class: :string,
67
51
  identifier: true,
52
+ read_only: true,
68
53
  aliases: [:name]
69
54
  },
70
55
 
71
56
  # @!attribute [r] region
72
57
  # @return [String]
73
58
  region: {
74
- class: :string
59
+ class: :string,
60
+ read_only: true
75
61
  }
76
62
  }.freeze
77
63
  parse_object_model
@@ -83,7 +69,7 @@ module Jamf
83
69
  #
84
70
  # Note that ISO8601 accepts the formats: +/-hh:mm, +/-hhmm, or +/-hh
85
71
  #
86
- # @return [Integer] The offset from UTC, as a string
72
+ # @return [String] The offset from UTC, as a string
87
73
  #
88
74
  def utc_offset_str
89
75
  return @utc_offset_str if @utc_offset_str
@@ -114,6 +100,6 @@ module Jamf
114
100
  othertime.getlocal utc_offset
115
101
  end
116
102
 
117
- end # class
103
+ end # class TimeZone
118
104
 
119
105
  end # module
@@ -24,35 +24,53 @@
24
24
 
25
25
  module Jamf
26
26
 
27
- # This mixin should be extended in abstract class definitions
28
- # it will raise an error if those classes are instantiated.
27
+ # This mixin should be extended in base class definitions
28
+ # it will raise an error if those classes are instantiated or allocated
29
29
  # It also maintains an array of classes that extend themselves this way
30
- # and are abstract.
31
- module Abstract
30
+ #
31
+ module BaseClass
32
+
33
+ DEFAULT_ACTION = 'access the API'.freeze
34
+ ALLOCATION_ACTION = 'be allocated'.freeze
35
+ INSTANTIATION_ACTION = 'be instantiated'.freeze
32
36
 
33
37
  # when a class is extended by this module, it
34
- # gets added to the array of known abstract classes
38
+ # gets added to the array of known base classes
35
39
  def self.extended(by_class)
36
- abstract_classes << by_class
40
+ base_classes << by_class
37
41
  end
38
42
 
39
- # Classes will be added to this array as they are exteded by Abstract
40
- def self.abstract_classes
41
- @abstract_classes ||= []
43
+ # Classes will be added to this array as they are exteded by BaseClass
44
+ def self.base_classes
45
+ @base_classes ||= []
42
46
  end
43
47
 
44
- def self.abstract?
45
- abstract_classes.include? self
48
+ # raise an exception if a given class is a base class
49
+ def self.stop_if_base_class(klass, action = DEFAULT_ACTION)
50
+ raise Jamf::UnsupportedError, "#{klass} is a base class and cannot #{action}." if base_classes.include? klass
46
51
  end
47
52
 
48
- # when any extended class or subclass of an extended class is instntiated
49
- # check that it isn't in the abstract list.
50
- def new(*args, &block)
51
- raise Jamf::UnsupportedError, "Unsupported: #{self} is an abstract class, cannot be instantiated." if Jamf::Abstract.abstract_classes.include? self
53
+ def base_class?
54
+ Jamf::BaseClass.base_classes.include? self
55
+ end
52
56
 
57
+ # Can't allocate if base class
58
+ def allocate(*args, &block)
59
+ stop_if_base_class ALLOCATION_ACTION
53
60
  super
54
61
  end
55
62
 
56
- end # module Abstract
63
+ # Can't instantiate if base_class
64
+ def new(*args, &block)
65
+ stop_if_base_class INSTANTIATION_ACTION
66
+ super
67
+ end
68
+
69
+ # raise an exception if this class is a base class
70
+ def stop_if_base_class(action = DEFAULT_ACTION)
71
+ Jamf::BaseClass.stop_if_base_class self, action
72
+ end
73
+
74
+ end # module BaseClass
57
75
 
58
76
  end # Jamf
@@ -24,14 +24,35 @@
24
24
 
25
25
  module Jamf
26
26
 
27
- # This mixin overrides JSONObject.mutable? to return false,
28
- # meaning that no setters are ever defined, and if the
29
- # object is a Jamf::Resource, #save will raise an error
27
+ # This mixin implements the .../delete-multiple endpoints that
28
+ # some collection resources have (and eventually all will??)
29
+ # It should be extended into classes representing those resources
30
30
  #
31
- module Immutable
31
+ module BulkDeletable
32
32
 
33
- def mutable?
34
- false
33
+ DELETE_MULTIPLE_ENDPOINT = 'delete-multiple'.freeze
34
+
35
+ # Delete multiple objects by providing an array of their
36
+ #
37
+ # @param ids [Array<String,Integer>] The ids to delete
38
+ #
39
+ # @param cnx [Jamf::Connection] The connection to use, default: Jamf.cnx
40
+ #
41
+ # @return [Array<Jamf::Connection::APIError::ErrorInfo] Info about any ids
42
+ # that failed to be deleted.
43
+ #
44
+ def bulk_delete(ids, cnx: Jamf.cnx)
45
+ ids = [ids] unless ids.is_a? Array
46
+ request_body = { ids: ids.map(&:to_s) }
47
+
48
+ begin
49
+ cnx.post "#{rsrc_path}/#{DELETE_MULTIPLE_ENDPOINT}", request_body
50
+ []
51
+ rescue Jamf::Connection::APIError => e
52
+ raise e unless e.httpStatus == 400
53
+
54
+ e.errors
55
+ end
35
56
  end
36
57
 
37
58
  end # Lockable
@@ -33,7 +33,7 @@ module Jamf
33
33
  # have a real 'notes' or 'description' field, like policies.
34
34
  #
35
35
  # In the Jamf Pro API, this history is usually available at a resource path
36
- # ending with '/history'
36
+ # ending with '/history' (see NON-STANDARD 'history' Paths below)
37
37
  #
38
38
  # Due to the many kinds of history available in Jamf, like management
39
39
  # history, application usage history, and so on, ruby-jss uses the term
@@ -49,49 +49,32 @@ module Jamf
49
49
  # - SingletonResources (e.g. Client Checkin Settings )
50
50
  # - mix-in this module by including AND extending, to get both
51
51
  #
52
- # This module will add two methods:
52
+ # ##### NON-STANDARD 'history' Paths
53
+ # For most classes, the change log path is the #rsrc_path with '/history'
54
+ # appended, and in that case it will be determined automatically.
55
+ # If the object has some other path for the change log, e.g.
56
+ # InventoryPreloadRecord, the class can define a constant CHANGE_LOG_RSRC
57
+ # with the non-standard path. If that constant is defined, it will be used.
53
58
  #
54
- # 1) #change_log, will fetch and cache an Array of readonly
55
- # Jamf::ChangeLogEntry instances. passing any truthy parameter will
56
- # cause it to re-fetch the Array from the server.
57
59
  #
58
- # 2) #add_history_note(note), which takes a string and adds it to the
59
- # object's change history as a note and re-fetches & caches the history.
60
+ # This module will add these public methods:
61
+ #
62
+ # 1) #change_log, will fetch an Array of readonly
63
+ # Jamf::ChangeLogEntry instances. possibly sorted, filtered, paged,
64
+ # or cached
65
+ #
66
+ # 2) #next_page_of_change_log, will retrieve the next page of a paged
67
+ # #change_log call
68
+ #
69
+ # 3) #add_change_log_note(note), which takes a string and adds it to the
70
+ # object's change history as a note and clears the cached the logs.
60
71
  #
61
72
  module ChangeLog
62
73
 
63
- # TODO: note can have a max length of 2500 characters.
64
-
65
- # The change and note history for this resource.
66
- #
67
- # The history is cached internally and only re-fetched when
68
- # a truthy parameter is given.
69
- #
70
- # @param refresh[Boolean] re-fetch and re-cache the history
71
- #
72
- # @return [Array<Jamf::ChangeHistoryEntry>] The change and note history for
73
- # this resource
74
- #
75
- def change_log(refresh = false, cnx: Jamf.cnx)
76
- # this should only be true for instances of CollectionResources
77
- cnx = @cnx if @cnx
78
-
79
- @change_log = nil if refresh
80
- @change_log ||= cnx.get(change_log_rsrc)[:results].map! do |l|
81
- #
82
- # TODO: Report bug in jamf data, sometimes there's no details in the JSON
83
- # so add an empty string if needed. DO it for note too, just in case
84
- l[:details] ||= Jamf::BLANK
85
- l[:note] ||= Jamf::BLANK
86
-
87
- Jamf::ChangeLogEntry.new l
88
- end # map!
89
- end
90
-
91
74
  # Add a note to this resource's change log.
92
75
  #
93
- # If the change history has been cached already, it is
94
- # recached after adding the note.
76
+ # If the change history has been cached already, the cache is
77
+ # flushed after adding the note.
95
78
  #
96
79
  # @param note[String] The note to add. It cannot be empty.
97
80
  #
@@ -104,35 +87,202 @@ module Jamf
104
87
  note = Jamf::Validate.non_empty_string note
105
88
  note_to_send = { note: note }
106
89
  cnx.post change_log_rsrc, note_to_send
90
+
107
91
  # flush the cached data, force reload when next accessed, to get new note
108
92
  @change_log = nil
109
93
  end
110
94
 
95
+ # The change and note history for this resource.
96
+ # This is a collection of objects as a sub-resource of some
97
+ # primary resource. As such, retriving the change log returns
98
+ # an array of objects, and can be paged, sorted and filtered.
99
+ #
100
+ # This method is very similar to CollectionResource.all, see the
101
+ # docs for that method for more details
102
+ #
103
+ # @param sort [String, Array<String>] Server-side sorting criteria in the format:
104
+ # property:direction, where direction is 'asc' or 'desc'. Multiple
105
+ # properties are supported, either as separate strings in an Array, or
106
+ # a single string, comma separated.
107
+ #
108
+ # @param filter [String] An RSQL filter string. Not all change_log resources
109
+ # currently support filters, and if they don't, this will be ignored.
110
+ #
111
+ # @param paged [Boolean] Defaults to false. Returns only the first page of
112
+ # `page_size` log entries. Use {.next_page_of_change_log} to retrieve each
113
+ # successive page.
114
+ #
115
+ # @param page_size [Integer] How many log entries are returned per page?
116
+ # Minimum is 1, maximum is 2000, default is 100. Ignored unless paged: is
117
+ # truthy.
118
+ # Note: the final page may contain fewer entries than the page_size
119
+ #
120
+ # @param refresh [Boolean] re-fetch and re-cache the full list of all entries.
121
+ # Ignored if paged:, page_size:, sort:, or filter: are used.
122
+ #
123
+ # @param cnx [Jamf::Connection] The API connection to use, default: Jamf.cnx.
124
+ # If this is an instance of a Collection Resource, this is always
125
+ # the connection from which it was fetched.
126
+ #
127
+ # @return [Array<Jamf::ChangeLogEntry>] The change log entries requested
128
+ #
129
+ def change_log(sort: nil, filter: nil, paged: nil, page_size: nil, refresh: false, cnx: Jamf.cnx)
130
+ # this should only be true for instances of CollectionResources
131
+ cnx = @cnx if @cnx
132
+
133
+ # use the cache if not paging, filtering or sorting
134
+ return cached_change_log(refresh, cnx) if !paged && !sort && !filter
135
+
136
+ sort = parse_change_log_sort(sort)
137
+
138
+ filter &&= "&filter=#{CGI.escape filter.to_s}"
139
+
140
+ return first_change_log_page(page_size, sort, filter, cnx) if paged
141
+
142
+ fetch_all_change_log_entries(sort, filter, cnx)
143
+ end
144
+
145
+ # Fetch the next page of a paged #change_log request
146
+ # Returns an empty array if there's been no paged request
147
+ # or if the last one has no more pages.
148
+ #
149
+ # @return [Array<Jamf::ChangeHistoryEntry>] The next page of the change
150
+ # and note history for this resource
151
+ #
152
+ def next_page_of_change_log
153
+ case @change_log_page
154
+ when :first
155
+ @change_log_page = 0
156
+ when Integer
157
+ @change_log_page += 1
158
+ else
159
+ # if here, we haven't initiated a paged request, or
160
+ # all pages have already been delivered
161
+ return []
162
+ end
163
+
164
+ raw = @change_log_paged_cnx.get "#{change_log_rsrc}?page=#{@change_log_page}&page-size=#{@change_log_page_size}#{@change_log_sort}#{@change_log_filter}"
165
+
166
+ @change_log_paged_fetched_count += raw[:results].size
167
+ @change_log_paged_total_count = raw[:totalCount]
168
+
169
+ # did we get the last of them in the this page?
170
+ # if so, clear all the paging data
171
+ clear_change_log_paging_data if @change_log_paged_fetched_count >= @change_log_paged_total_count
172
+
173
+ # return the page results
174
+ raw[:results].map { |le| Jamf::ChangeLogEntry.new le }
175
+ end
176
+
177
+ # how many change log entries are there?
178
+ # needed when using paged #change_log calls
179
+ #
180
+ # @param cnx [Jamf::Connection] The API connection to use, default: Jamf.cnx
181
+ # This is ignored for instances of Collection Resources, which always use
182
+ # the same connection from which they were fetched.
183
+ #
184
+ # @return [Integer] How many changelog entries exist?
185
+ #
186
+ def change_log_count(cnx: Jamf.cnx)
187
+ cnx = @cnx if @cnx
188
+ cnx.get("#{change_log_rsrc}?page=0&page-size=1")[:totalCount]
189
+ end
190
+
111
191
  # Private methods
112
192
  ###########################
193
+
113
194
  private
114
195
 
115
- # TODO: Implement paging
196
+ # @return [String] The rest resource to get change logs for this object
197
+ #
116
198
  def change_log_rsrc
117
- @change_log_rsrc ||= "#{rsrc_path}/history"
199
+ @change_log_rsrc ||= defined?(self::CHANGE_LOG_RSRC) ? self::CHANGE_LOG_RSRC : "#{rsrc_path}/history"
200
+ end
201
+
202
+ def parse_change_log_sort(sort)
203
+ case sort
204
+ when nil
205
+ sort
206
+ when String
207
+ "&sort=#{CGI.escape sort}"
208
+ when Array
209
+ "&sort=#{CGI.escape sort.join(',')}"
210
+ else
211
+ raise ArgumentError, 'sort criteria must be a String or Array of Strings'
212
+ end
213
+ end
214
+
215
+ # get the first page of a paged change log request, and set up for
216
+ # getting later pages
217
+ #
218
+ # @param page_size [Integer] how many items per page
219
+ #
220
+ # @param sort [String,Array<String>] server-side sorting parameters
221
+ #
222
+ # @param filter [String] RSQL String limiting the result set
223
+ #
224
+ # @param cnx [Jamf::Connection] The API connection to use
225
+ #
226
+ # @return [Array<Object>] The first page of the change logs for this resource
227
+ #
228
+ def first_change_log_page(page_size, sort, filter, cnx)
229
+ page_size ||= Jamf::Pageable::DFT_PAGE_SIZE
230
+ raise ArgumentError, "page_size must be an Integer from #{MIN_PAGE_SIZE} to #{MAX_PAGE_SIZE}" unless Jamf::Pageable::PAGE_SIZE_RANGE.include? page_size
231
+
232
+ # set all these values then call for the next page
233
+ @change_log_paged_cnx = cnx
234
+ @change_log_page = :first
235
+ @change_log_page_size = page_size
236
+ @change_log_sort = sort
237
+ @change_log_filter = filter
238
+ @change_log_paged_fetched_count = 0
239
+ next_page_of_change_log
240
+ end
241
+
242
+ def clear_change_log_paging_data
243
+ @change_log_paged_cnx = nil
244
+ @change_log_page = nil
245
+ @change_log_page_size = nil
246
+ @change_log_sort = nil
247
+ @change_log_filter = nil
248
+ @change_log_paged_total_count = nil
249
+ @change_log_paged_fetched_count = nil
118
250
  end
119
251
 
120
- # def change_log_rsrc(page: nil, size: nil)
121
- # params = ''
122
- # params << '?' if page || size
123
- # if page
252
+ # return the cached/cachable version of .change_log
124
253
  #
125
- # end
254
+ # @param refresh [Boolean] refetch the cache from the server?
126
255
  #
127
- # if size
256
+ # @param cnx [Jamf::Connection] The Connection to use
128
257
  #
129
- # end
130
- # params << '?' if page || size
131
- # params << '?' if page || size
258
+ # @return [Array<Jamf::ChangeLogEntry>] All the change_log entries
132
259
  #
133
- # @change_log_rsrc ||= "#{rsrc_path}/history"
134
- # end
260
+ def cached_change_log(refresh, cnx)
261
+ @change_log = nil if refresh
262
+ return @change_log if @change_log
263
+
264
+ sort = nil
265
+ filter = nil
266
+ @change_log = fetch_all_change_log_entries(sort, filter, cnx)
267
+ end
268
+
269
+ def fetch_all_change_log_entries(sort, filter, cnx)
270
+ cnx = @cnx if @cnx
271
+ paged_rsrc = "#{change_log_rsrc}?page-size=#{Jamf::Pageable::MAX_PAGE_SIZE}#{sort}#{filter}"
272
+ page = 0
273
+
274
+ raw = cnx.get "#{paged_rsrc}&page=#{page}"
275
+ results = raw[:results]
276
+
277
+ until results.size >= raw[:totalCount]
278
+ page += 1
279
+ raw = cnx.get "#{paged_rsrc}&page=#{page}"
280
+ results += raw[:results]
281
+ end
282
+ results.map { |le| Jamf::ChangeLogEntry.new le }
283
+ end
284
+
135
285
 
136
- end # module ChangeHistory
286
+ end # module ChangeLog
137
287
 
138
288
  end # module