ruby-jss 1.2.3 → 1.2.4a1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jamf.rb +169 -0
  3. data/lib/jamf/api/abstract_classes/collection_resource.rb +422 -0
  4. data/lib/jamf/api/abstract_classes/generic_reference.rb +145 -0
  5. data/lib/jamf/api/abstract_classes/json_object.rb +1074 -0
  6. data/lib/jamf/api/abstract_classes/prestage.rb +219 -0
  7. data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +126 -0
  8. data/lib/jamf/api/abstract_classes/resource.rb +250 -0
  9. data/lib/jamf/api/abstract_classes/singleton_resource.rb +87 -0
  10. data/lib/jamf/api/attribute_classes/ip_address.rb +66 -0
  11. data/lib/jamf/api/attribute_classes/timestamp.rb +144 -0
  12. data/lib/jamf/api/connection.rb +734 -0
  13. data/lib/jamf/api/connection/api_error.rb +111 -0
  14. data/lib/jamf/api/connection/api_error_styleguide.rb +96 -0
  15. data/lib/jamf/api/connection/token.rb +220 -0
  16. data/lib/jamf/api/json_objects/account_prefs.rb +79 -0
  17. data/lib/jamf/api/json_objects/android_details.rb +139 -0
  18. data/lib/jamf/api/json_objects/appletv_details.rb +110 -0
  19. data/lib/jamf/api/json_objects/attachment.rb +68 -0
  20. data/lib/jamf/api/json_objects/cellular_network.rb +151 -0
  21. data/lib/jamf/api/json_objects/change_log_entry.rb +77 -0
  22. data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +67 -0
  23. data/lib/jamf/api/json_objects/country.rb +51 -0
  24. data/lib/jamf/api/json_objects/extension_attribute_value.rb +128 -0
  25. data/lib/jamf/api/json_objects/installed_application.rb +59 -0
  26. data/lib/jamf/api/json_objects/installed_certificate.rb +53 -0
  27. data/lib/jamf/api/json_objects/installed_configuration_profile.rb +67 -0
  28. data/lib/jamf/api/json_objects/installed_ebook.rb +58 -0
  29. data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +59 -0
  30. data/lib/jamf/api/json_objects/inventory_preload_extension_attribute.rb +52 -0
  31. data/lib/jamf/api/json_objects/ios_details.rb +244 -0
  32. data/lib/jamf/api/json_objects/location.rb +95 -0
  33. data/lib/jamf/api/json_objects/md_prestage_name.rb +57 -0
  34. data/lib/jamf/api/json_objects/md_prestage_names.rb +82 -0
  35. data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +165 -0
  36. data/lib/jamf/api/json_objects/mobile_device_details.rb +219 -0
  37. data/lib/jamf/api/json_objects/mobile_device_security.rb +101 -0
  38. data/lib/jamf/api/json_objects/prestage_assignment.rb +61 -0
  39. data/lib/jamf/api/json_objects/prestage_location.rb +104 -0
  40. data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +132 -0
  41. data/lib/jamf/api/json_objects/prestage_scope.rb +54 -0
  42. data/lib/jamf/api/json_objects/prestage_sync_status.rb +63 -0
  43. data/lib/jamf/api/json_objects/purchasing_data.rb +125 -0
  44. data/lib/jamf/api/mixins/abstract.rb +58 -0
  45. data/lib/jamf/api/mixins/bulk_deletable.rb +39 -0
  46. data/lib/jamf/api/mixins/change_log.rb +136 -0
  47. data/lib/jamf/api/mixins/extendable.rb +75 -0
  48. data/lib/jamf/api/mixins/immutable.rb +39 -0
  49. data/lib/jamf/api/mixins/locatable.rb +124 -0
  50. data/lib/jamf/api/mixins/lockable.rb +48 -0
  51. data/lib/jamf/api/mixins/referable.rb +92 -0
  52. data/lib/jamf/api/mixins/searchable.rb +202 -0
  53. data/lib/jamf/api/mixins/uncreatable.rb +40 -0
  54. data/lib/jamf/api/mixins/undeletable.rb +40 -0
  55. data/lib/jamf/api/resources/collection_resources/account.rb +163 -0
  56. data/lib/jamf/api/resources/collection_resources/building.rb +114 -0
  57. data/lib/jamf/api/resources/collection_resources/category.rb +82 -0
  58. data/lib/jamf/api/resources/collection_resources/computer.rb +49 -0
  59. data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +80 -0
  60. data/lib/jamf/api/resources/collection_resources/department.rb +79 -0
  61. data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +45 -0
  62. data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +274 -0
  63. data/lib/jamf/api/resources/collection_resources/md_prestage.rb +139 -0
  64. data/lib/jamf/api/resources/collection_resources/mobile_device.rb +315 -0
  65. data/lib/jamf/api/resources/collection_resources/script.rb +190 -0
  66. data/lib/jamf/api/resources/collection_resources/site.rb +77 -0
  67. data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +131 -0
  68. data/lib/jamf/api/resources/singleton_resources/authorization.rb +88 -0
  69. data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +139 -0
  70. data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +95 -0
  71. data/lib/jamf/client.rb +301 -0
  72. data/lib/jamf/client/jamf_binary.rb +132 -0
  73. data/lib/jamf/client/jamf_helper.rb +298 -0
  74. data/lib/jamf/client/management_action.rb +114 -0
  75. data/lib/jamf/compatibility.rb +88 -0
  76. data/lib/jamf/composer.rb +190 -0
  77. data/lib/jamf/configuration.rb +281 -0
  78. data/lib/jamf/exceptions.rb +107 -0
  79. data/lib/jamf/ruby_extensions.rb +36 -0
  80. data/lib/jamf/ruby_extensions/array.rb +35 -0
  81. data/lib/jamf/ruby_extensions/array/predicates.rb +46 -0
  82. data/lib/jamf/ruby_extensions/array/utils.rb +47 -0
  83. data/lib/jamf/ruby_extensions/filetest.rb +32 -0
  84. data/lib/jamf/ruby_extensions/filetest/predicates.rb +46 -0
  85. data/lib/jamf/ruby_extensions/hash.rb +33 -0
  86. data/lib/jamf/ruby_extensions/hash/backports.rb +92 -0
  87. data/lib/jamf/ruby_extensions/ipaddr.rb +37 -0
  88. data/lib/jamf/ruby_extensions/ipaddr/utils.rb +95 -0
  89. data/lib/jamf/ruby_extensions/object.rb +30 -0
  90. data/lib/jamf/ruby_extensions/object/predicates.rb +51 -0
  91. data/lib/jamf/ruby_extensions/pathname.rb +39 -0
  92. data/lib/jamf/ruby_extensions/pathname/predicates.rb +50 -0
  93. data/lib/jamf/ruby_extensions/pathname/utils.rb +75 -0
  94. data/lib/jamf/ruby_extensions/string.rb +35 -0
  95. data/lib/jamf/ruby_extensions/string/backports.rb +66 -0
  96. data/lib/jamf/ruby_extensions/string/conversions.rb +65 -0
  97. data/lib/jamf/ruby_extensions/string/predicates.rb +47 -0
  98. data/lib/jamf/utility.rb +423 -0
  99. data/lib/jamf/validate.rb +224 -0
  100. data/lib/jamf/version.rb +32 -0
  101. data/lib/jpapi.rb +26 -0
  102. data/lib/jss/version.rb +1 -1
  103. metadata +104 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db7db3a85a2ce09946ec84f4b254f948f566daa8f5e0e9b8f939c9efb8eefef1
4
- data.tar.gz: 1edb35f947212312c165f2ff0fa1ed3c4a059fb58f0abb5de9bea8877bfab3a0
3
+ metadata.gz: 25d16b4c34d2790bdf6175543f81a2125e80ddf0c2c49cbb76d340b76dd562df
4
+ data.tar.gz: a09cfceaaecd6c3109cafbd0d7912a1c66326c6c5ddaae479a4260816c50ede9
5
5
  SHA512:
6
- metadata.gz: d8d61d9f03d99a289f0b5c4dd0fefe246f824fac21003e905bbc5dd25c6e2ff84bffbc6eb3244086db8af143ca39722e738711c82cf5f8b9174c6183d8c40d03
7
- data.tar.gz: db954707cef1f340613ecb27657d38673e6117ac4b9db05ba3025bab6ba4446e220808346856e4c50003eca58fc84dfb8c6e640d2a41e3a32987e9dc5766a99a
6
+ metadata.gz: fb2e1e6fb575db16ade4b819bbea3cfb73ce6956c1012569f2be10d757ed05f31c4671605065a6c619667afa3a2540119af0afee5cf506d1ae8455d4aa42d4c0
7
+ data.tar.gz: 4af7406b1457c0c70d4873578920938b942ed7b6ea15702898f74450453720f30b24803addf8762426f617b7e223ef34ae2d51453df5cf283da35c32d27a8854
@@ -0,0 +1,169 @@
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
+ #
25
+
26
+ #
27
+ # JAMF, A Ruby module for interacting with a JAMF Pro Server via the JAMF API
28
+ #
29
+
30
+ ### Standard Libraries
31
+ require 'English'
32
+ require 'json'
33
+ require 'yaml'
34
+ require 'pathname'
35
+ require 'time'
36
+ require 'singleton'
37
+ require 'open-uri'
38
+ require 'ipaddr'
39
+ require 'base64'
40
+ require 'shellwords'
41
+ require 'digest'
42
+ require 'open3'
43
+
44
+
45
+ ### Gems
46
+ require 'rest-client'
47
+ require 'plist'
48
+
49
+ # Used, among other places, in the Connection::APIError class
50
+ require 'immutable-struct'
51
+
52
+ # TODO: needed?
53
+ # require 'recursive-open-struct'
54
+
55
+ # non-api parts of Jamf module
56
+ require 'jamf/configuration'
57
+ require 'jamf/exceptions'
58
+ require 'jamf/utility'
59
+ require 'jamf/validate'
60
+ require 'jamf/version'
61
+
62
+ # backports and extensions to existing Ruby classes
63
+ require 'jamf/compatibility'
64
+ require 'jamf/ruby_extensions'
65
+
66
+ # API connection
67
+ require 'jamf/api/connection'
68
+
69
+
70
+ # The main module.
71
+ # See README.md
72
+ #
73
+ module Jamf
74
+
75
+ # The minimum Ruby version that works with this gem
76
+ # 2.3 allows us to start using some nice features like the safe-navigation
77
+ # operator and Array#dig & Hash#dig, and such.
78
+ #
79
+ # For a list of features, see https://github.com/ruby/ruby/blob/v2_3_0/NEWS
80
+ # and http://nithinbekal.com/posts/ruby-2-3-features/
81
+ #
82
+ MINIMUM_RUBY_VERSION = '2.3'.freeze
83
+
84
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new(MINIMUM_RUBY_VERSION)
85
+ raise "Can't use the JAMF module, ruby itself must be version #{MINIMUM_RUBY_VERSION} or greater."
86
+ end
87
+
88
+ # AUTOLOADING
89
+ ##################################
90
+
91
+ # Top-level API Abstract Classes
92
+ autoload :JSONObject, 'jamf/api/abstract_classes/json_object'
93
+ autoload :Resource, 'jamf/api/abstract_classes/resource'
94
+ autoload :SingletonResource, 'jamf/api/abstract_classes/singleton_resource'
95
+ autoload :CollectionResource, 'jamf/api/abstract_classes/collection_resource'
96
+
97
+ # Abstract Classes used for JSONObject subclasses
98
+ autoload :Prestage, 'jamf/api/abstract_classes/prestage'
99
+ autoload :PrestageSkipSetupItems, 'jamf/api/abstract_classes/prestage_skip_setup_items'
100
+
101
+ # Abstract Classes not used for JSONObject subclasses
102
+ autoload :GenericReference, 'jamf/api/abstract_classes/generic_reference'
103
+
104
+ # MixIn Modules
105
+ autoload :ChangeLog, 'jamf/api/mixins/change_log'
106
+ autoload :Extendable, 'jamf/api/mixins/extendable'
107
+ autoload :Locatable, 'jamf/api/mixins/locatable'
108
+ autoload :Referable, 'jamf/api/mixins/referable'
109
+ autoload :Searchable, 'jamf/api/mixins/searchable'
110
+ autoload :Lockable, 'jamf/api/mixins/lockable'
111
+ autoload :UnCreatable, 'jamf/api/mixins/uncreatable'
112
+ autoload :Immutable, 'jamf/api/mixins/immutable'
113
+ autoload :UnDeletable, 'jamf/api/mixins/undeletable'
114
+ autoload :Abstract, 'jamf/api/mixins/abstract'
115
+
116
+ # Utility modules
117
+ autoload :Validate, 'jamf/validate'
118
+
119
+ # Subclasses of JSONObject, but not Resource
120
+ autoload :AndroidDetails, 'jamf/api/json_objects/android_details'
121
+ autoload :AppleTVDetails, 'jamf/api/json_objects/appletv_details'
122
+ autoload :CellularNetwork, 'jamf/api/json_objects/cellular_network'
123
+ autoload :ChangeLogEntry, 'jamf/api/json_objects/change_log_entry'
124
+ autoload :ComputerPrestageSkipSetupItems, 'jamf/api/json_objects/computer_prestage_skip_setup_items'
125
+ autoload :Country, 'jamf/api/json_objects/country'
126
+ autoload :ExtensionAttributeValue, 'jamf/api/json_objects/extension_attribute_value'
127
+ autoload :InstalledApplication, 'jamf/api/json_objects/installed_application'
128
+ autoload :InstalledCertificate, 'jamf/api/json_objects/installed_certificate'
129
+ autoload :InstalledConfigurationProfile, 'jamf/api/json_objects/installed_configuration_profile'
130
+ autoload :InstalledEBook, 'jamf/api/json_objects/installed_ebook'
131
+ autoload :InstalledProvisioningProfile, 'jamf/api/json_objects/installed_provisioning_profile'
132
+ autoload :InventoryPreloadExtensionAttribute, 'jamf/api/json_objects/inventory_preload_extension_attribute'
133
+ autoload :IosDetails, 'jamf/api/json_objects/ios_details'
134
+ autoload :Location, 'jamf/api/json_objects/location'
135
+ autoload :PrestageLocation, 'jamf/api/json_objects/prestage_location'
136
+ autoload :PrestageSyncStatus, 'jamf/api/json_objects/prestage_sync_status'
137
+ autoload :MobileDeviceDetails, 'jamf/api/json_objects/mobile_device_details'
138
+ autoload :MobileDeviceSecurity, 'jamf/api/json_objects/mobile_device_security'
139
+ autoload :MobileDevicePrestageName, 'jamf/api/json_objects/md_prestage_name'
140
+ autoload :MobileDevicePrestageNames, 'jamf/api/json_objects/md_prestage_names'
141
+ autoload :MobileDevicePrestageSkipSetupItems, 'jamf/api/json_objects/md_prestage_skip_setup_items'
142
+ autoload :PurchasingData, 'jamf/api/json_objects/purchasing_data'
143
+ autoload :PrestagePurchasingData, 'jamf/api/json_objects/prestage_purchasing_data'
144
+ autoload :PrestageScope, 'jamf/api/json_objects/prestage_scope'
145
+ autoload :PrestageAssignment, 'jamf/api/json_objects/prestage_assignment'
146
+
147
+ # Subclasses of SingletonResource
148
+ autoload :ClientCheckInSettings, 'jamf/api/resources/singleton_resources/client_checkin_settings'
149
+ autoload :ReEnrollmentSettings, 'jamf/api/resources/singleton_resources/reenrollment_settings'
150
+ autoload :AppStoreCountryCodes, 'jamf/api/resources/singleton_resources/app_store_country_codes'
151
+
152
+ # Subclasses of CollectionResource
153
+ autoload :Attachment, 'jamf/api/resources/collection_resources/attachment'
154
+ autoload :Building, 'jamf/api/resources/collection_resources/building'
155
+ autoload :Computer, 'jamf/api/resources/collection_resources/computer'
156
+ autoload :ComputerPrestage, 'jamf/api/resources/collection_resources/computer_prestage'
157
+ autoload :Department, 'jamf/api/resources/collection_resources/department'
158
+ autoload :ExtensionAttribute, 'jamf/api/resources/collection_resources/extension_attribute'
159
+ autoload :InventoryPreloadRecord, 'jamf/api/resources/collection_resources/inventory_preload_record'
160
+ autoload :MobileDevice, 'jamf/api/resources/collection_resources/mobile_device'
161
+ autoload :MobileDevicePrestage, 'jamf/api/resources/collection_resources/md_prestage'
162
+ autoload :Site, 'jamf/api/resources/collection_resources/site'
163
+ autoload :Script, 'jamf/api/resources/collection_resources/script'
164
+
165
+ # other classes used as attributes inside the resource classes
166
+ autoload :IPAddress, 'jamf/api/attribute_classes/ip_address'
167
+ autoload :Timestamp, 'jamf/api/attribute_classes/timestamp'
168
+
169
+ end # module
@@ -0,0 +1,422 @@
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
+ #
25
+
26
+ # The module
27
+ module Jamf
28
+
29
+ # A Collection Resource in Jamf Pro
30
+ #
31
+ # See {Jamf::Resource} for general info about API resources.
32
+ #
33
+ # Collection resources have more than one resource within them, and those
34
+ # can (usually) be created and deleted as well as fetched and updated.
35
+ # The entire collection (or a part of it) can also be fetched as an Array.
36
+ # When the whole collection is fetched, the result is cached for future use.
37
+ #
38
+ # # Subclassing
39
+ #
40
+ # ## Creatability, & Deletability
41
+ #
42
+ # Sometimes the API doesn't support creation of new members of the collection.
43
+ # If that's the case, just extend the subclass with Jamf::UnCreatable
44
+ # and the '.create' class method will raise an error.
45
+ #
46
+ # Similarly for deletion of members: if the API doesn't have a way to delete
47
+ # them, extend the subclass with Jamf::UnDeletable
48
+ #
49
+ # See also Jamf::JSONObject, which talks about extending subclasses
50
+ # with Jamf::Immutable
51
+ #
52
+ # ## Bulk Deletion
53
+ #
54
+ # Some collection resources have a resource for bulk deletion, passing in
55
+ # a JSON array of ids to delete.
56
+ #
57
+ # If so, just define a BULK_DELETE_RSRC, and the .delete class method
58
+ # will use it, rather than making multiple calls to delete individual
59
+ # items. See Jamf::Category::BULK_DELETE_RSRC for an example
60
+ #
61
+ # @abstract
62
+ #
63
+ class CollectionResource < Jamf::Resource
64
+
65
+ extend Jamf::Abstract
66
+ include Comparable
67
+
68
+ # Public Class Methods
69
+ #####################################
70
+
71
+ # @return [Array<Symbol>] the attribute names that are marked as identifiers
72
+ #
73
+ def self.identifiers
74
+ self::OBJECT_MODEL.select { |_attr, deets| deets[:identifier] }.keys
75
+ end
76
+
77
+ # An array of attribute names that are required when
78
+ # making new CollectionResources
79
+ # See the OBJECT_MODEL documentation in {Jamf::JSONObject}
80
+ def self.required_attributes
81
+ self::OBJECT_MODEL.select { |_attr, deets| deets[:required] }.keys
82
+ end
83
+
84
+ # The Collection members Array for this class, retrieved from
85
+ # the RSRC_PATH as Parsed JSON, but not instantiated into instances
86
+ # unless instantiate: is truthy.
87
+ #
88
+ # E.g. for {Jamf::Settings::Building}, this would be the Array of Hashes
89
+ # returned by GETing the resource .../settings/obj/building
90
+ #
91
+ # This Array is cached in the {Jamf::Connection} instance used to
92
+ # retrieve it, and future calls to .all will return the cached Array
93
+ # unless refresh is truthy.
94
+ #
95
+ # TODO: Investigate https://www.rubydoc.info/github/mloughran/api_cache
96
+ #
97
+ # @param refresh[Boolean] re-read the data from the API?
98
+ #
99
+ # @param cnx[Jamf::Connection] an API connection to use for the query.
100
+ # Defaults to the corrently active connection. See {Jamf::Connection}
101
+ #
102
+ # @param instantiate[Boolean] The Array contains instances of this class
103
+ # rather than the JSON Hashes from the API.
104
+ #
105
+ # @return [Array<Object>] An Array of all objects of this class in the JSS.
106
+ #
107
+ def self.all(refresh = false, cnx: Jamf.cnx, instantiate: false)
108
+ validate_not_abstract
109
+ cnx.collection_cache[self] = nil if refresh
110
+ return cnx.collection_cache[self] if cnx.collection_cache[self]
111
+
112
+ raw = cnx.get rsrc_path
113
+ cnx.collection_cache[self] =
114
+ if raw.is_a?(Hash) && raw[:results]
115
+ raw[:results]
116
+ else
117
+ raw
118
+ end
119
+
120
+ return cnx.collection_cache[self] unless instantiate
121
+
122
+ cnx.collection_cache[self].map { |m| new m }
123
+ end
124
+
125
+ # An array of the ids for all collection members
126
+ #
127
+ # @param refresh (see .all)
128
+ #
129
+ # @param cnx (see .all)
130
+ #
131
+ # @return [Array<Integer>]
132
+ #
133
+ def self.all_ids(refresh = false, cnx: Jamf.cnx)
134
+ all(refresh, cnx: cnx).map { |m| m[:id] }
135
+ end
136
+
137
+ # rubocop:disable Naming/UncommunicativeMethodParamName
138
+
139
+ # A Hash of all members of this collection where the keys are some
140
+ # identifier and values are any other attribute.
141
+ #
142
+ # @param ident [Symbol] An identifier of this Class, used as the key
143
+ # for the mapping Hash.
144
+ #
145
+ # @param to [Symbol] The attribute to which the ident will be mapped
146
+ #
147
+ # @param refresh (see .all)
148
+ #
149
+ # @param cnx (see .all)
150
+ #
151
+ # @return [Hash {Symbol: Object}] A Hash of identifier mapped to attribute
152
+ #
153
+ def self.map_all(ident, to:, cnx: Jamf.cnx, refresh: false)
154
+ raise Jamf::InvalidDataError, "No identifier #{ident} for class #{self}" unless
155
+ identifiers.include? ident
156
+
157
+ raise Jamf::NoSuchItemError, "No attribute #{to} for class #{self}" unless self::OBJECT_MODEL.key? to
158
+
159
+ list = all refresh, cnx: cnx
160
+ to_class = self::OBJECT_MODEL[to][:class]
161
+ mapped = list.map do |i|
162
+ [
163
+ i[ident],
164
+ to_class.is_a?(Symbol) ? i[to] : to_class.new(i[to])
165
+ ]
166
+ end # do i
167
+ mapped.to_h
168
+ end
169
+ # rubocop:enable Naming/UncommunicativeMethodParamName
170
+
171
+ # Given any identfier value for this collection, return the valid
172
+ # id, or nil if there's no match for the given value.
173
+ #
174
+ # If you know the value is a certain identifier, e.g. a serial_number
175
+ # then you can specify the identifier, for a faster search:
176
+ #
177
+ # valid_id serial_number: 'AB12DE34' # => Int or nil
178
+ #
179
+ # If you don't know wich identifier you have, just pass the value and
180
+ # all identifiers are searched
181
+ #
182
+ # valid_id 'AB12DE34' # => Int or nil
183
+ # valid_id 'SomeComputerName' # => Int or nil
184
+ #
185
+ # When the value is a string, the seach is case-insensitive
186
+ #
187
+ # TODO: When 'Searchability' is more dialed in via the searchable
188
+ # mixin, which implements enpoints like 'POST /v1/search-mobile-devices'
189
+ # then use that before using the 'all' list.
190
+ #
191
+ # @param value [Object] A value to search for as an identifier.
192
+ #
193
+ # @param refresh[Boolean] Reload the list data from the API
194
+ #
195
+ # @param ident: [Symbol] Restrict the search to this identifier.
196
+ # E.g. if :serial_number, then the value must be
197
+ # a known serial number, it is not checked against other identifiers
198
+ #
199
+ # @param cnx: (see .all)
200
+ #
201
+ # @return [Object, nil] the primary identifier of the matching object,
202
+ # or nil if it doesn't exist
203
+ #
204
+ def self.valid_id(value = nil, refresh: true, cnx: Jamf.cnx, **ident_hash)
205
+ unless ident_hash.empty?
206
+ ident, value = ident_hash.first
207
+ return id_from_other_ident ident, value, refresh, cnx: cnx
208
+ end
209
+
210
+ # check the id itself first
211
+ return value if all_ids(refresh, cnx: cnx).include? value
212
+
213
+ idents = identifiers - [:id]
214
+ val_is_str = value.is_a? String
215
+
216
+ idents.each do |ident|
217
+ match = all(cnx: cnx).select do |m|
218
+ val_is_str ? m[ident].to_s.casecmp?(value) : m[ident] == value
219
+ end.first
220
+ return match[:id] if match
221
+ end # identifiers.each do |ident|
222
+
223
+ nil
224
+ end
225
+
226
+ # Bu default, subclasses are creatable, i.e. new instances can be created
227
+ # with .create, and added to the JSS with .save
228
+ # If a subclass is NOT creatble for any reason, just add
229
+ # extend Jamf::UnCreatable
230
+ # and this method will return false
231
+ #
232
+ # @return [Boolean]
233
+ def self.creatable?
234
+ true
235
+ end
236
+
237
+ # Make a new thing to be added to the API
238
+ def self.create(params, cnx: Jamf.cnx)
239
+ raise Jamf::UnsupportedError, "#{self}'s are not currently creatable via the API" unless self.creatable?
240
+
241
+ validate_not_abstract
242
+
243
+ validate_required_attributes params
244
+
245
+ params.delete :id # no such animal when .creating
246
+ params[:creating_from_create] = true
247
+ new params, cnx: cnx
248
+ end
249
+
250
+ # Retrieve a member of a CollectionResource from the API
251
+ #
252
+ # To create new members to be added to the JSS, use
253
+ # {Jamf::CollectionResource.create}
254
+ #
255
+ # If you know the specific identifier attribute you're looking up, e.g.
256
+ # :id or :name or :udid, (or an aliase thereof) then you can specify it like
257
+ # `.fetch name: 'somename'`, or `.fetch udid: 'someudid'`
258
+ #
259
+ # If you don't know if (or don't want to type it) you can just use
260
+ # `.fetch 'somename'`, or `.fetch 'someudid'` and all identifiers will be
261
+ # searched for a match.
262
+ #
263
+ # @param ident_value[Object] A value for any identifier for this subclass.
264
+ # All identifier attributes will be searched for a match.
265
+ #
266
+ # @param cnx[Jamf::Connection] the connection to use to fetch the object
267
+ #
268
+ # @param ident_hash[Hash] an identifier attribute key and a search value
269
+ #
270
+ # @return [CollectionResource] The ruby-instance of a Jamf object
271
+ #
272
+ def self.fetch(ident_value = nil, cnx: Jamf.cnx, **ident_hash)
273
+ validate_not_abstract
274
+ id =
275
+ if ident_value == :random
276
+ all_ids.sample
277
+ elsif ident_value
278
+ valid_id ident_value
279
+ elsif ident_hash.empty?
280
+ nil
281
+ else
282
+ ident, lookup_value = ident_hash.first
283
+ valid_id ident => lookup_value
284
+ end
285
+
286
+ raise Jamf::NoSuchItemError, "No matching #{self}" unless id
287
+
288
+ data = cnx.get "#{rsrc_path}/#{id}"
289
+ new data, cnx: cnx
290
+ end # fetch
291
+
292
+ # By default, CollectionResource subclass instances are deletable.
293
+ # If not, just extend the subclass with Jamf::UnDeletable, and this
294
+ # will return false, and .delete & #delete will raise errors
295
+ def self.deletable?
296
+ true
297
+ end
298
+
299
+ # Delete one or more objects by identifier
300
+ # Any valid identifier for the class can be used (id, name, udid, etc)
301
+ # Identifiers can be provided as an array or as separate parameters
302
+ #
303
+ # e.g. .delete [1,3, 34, 4]
304
+ # or .delete 'myComputer', 'that-computer', 'OtherComputer'
305
+ #
306
+ # @param idents[Array<integer>, Integer]
307
+ #
308
+ # @param cnx[Jamf::Connection]
309
+ #
310
+ # @return [Array] the identifiers that were not found, so couldn't be deleted
311
+ #
312
+ def self.delete(*idents, cnx: Jamf.cnx)
313
+ raise Jamf::UnsupportedError, "Deleting #{self} objects is not currently supported" unless deletable?
314
+
315
+ idents.flatten!
316
+ no_valid_ids = []
317
+
318
+ idents.map do |ident|
319
+ id = valid_id ident
320
+ no_valid_ids << ident unless id
321
+ id
322
+ end
323
+ idents.compact!
324
+
325
+ # TODO: some rsrcs have a 'bulk delete' version...
326
+ idents.each { |id| cnx.delete "#{rsrc_path}/#{id}" }
327
+
328
+ no_valid_ids
329
+ end
330
+
331
+ # Private Class Methods
332
+ #####################################
333
+
334
+ # TODO: better pluralizing?
335
+ #
336
+ def self.create_list_methods(attr_name, attr_def)
337
+ list_method_name = "all_#{attr_name}s"
338
+
339
+ define_singleton_method(list_method_name) do |refresh = false, cnx: Jamf.cnx|
340
+ all_list = all(refresh, cnx: cnx)
341
+ if attr_def[:class].is_a? Symbol
342
+ all_list.map { |i| i[attr_name] }.uniq
343
+ else
344
+ all_list.map { |i| attr_def[:class].new i[attr_name] }
345
+ end
346
+ end # define_singleton_method
347
+
348
+ return unless attr_def[:aliases]
349
+
350
+ # aliases - TODO: is there a more elegant way?
351
+ attr_def[:aliases].each do |a|
352
+ define_singleton_method("all_#{a}s") do |refresh = false, cnx: Jamf.cnx|
353
+ send list_method_name, refresh, cnx: cnx
354
+ end # define_singleton_method
355
+ end # each alias
356
+ end # create_list_methods
357
+ private_class_method :create_list_methods
358
+
359
+ # validate that our .create data has the required attribute values.
360
+ # They can't be nil or empty.
361
+ #
362
+ def self.validate_required_attributes(data)
363
+ required_attributes.each do |atr|
364
+ raise Jamf::MissingDataError, "Required attribute '#{atr}:' may not be nil or empty" if data[atr].to_s.empty?
365
+ end
366
+ end
367
+ private_class_method :validate_required_attributes
368
+
369
+ # Given an indentier attr. key, and a value,
370
+ # return the id where that ident has that value, or nil
371
+ #
372
+ def self.id_from_other_ident(ident, value, refresh = true, cnx: Jamf.cnx)
373
+ raise ArgumentError, "Unknown identifier '#{ident}' for #{self}" unless identifiers.include? ident
374
+
375
+ # check the id itself first
376
+ return value if ident == :id && all_ids(refresh, cnx: cnx).include?(value)
377
+
378
+ # all ident values => ids
379
+ ident_map = map_all(ident, to: :id, cnx: cnx, refresh: refresh)
380
+
381
+ # case-insensitivity for string values
382
+ value = ident_map.keys.j_ci_fetch_string(value) if value.is_a? String
383
+
384
+ ident_map[value]
385
+ end
386
+ private_class_method :id_from_other_ident
387
+
388
+
389
+ # Instance Methods
390
+ #####################################
391
+
392
+ def exist?
393
+ !@id.nil?
394
+ end
395
+
396
+ def rsrc_path
397
+ return unless exist?
398
+ "#{self.class.rsrc_path}/#{@id}"
399
+ end
400
+
401
+ def delete
402
+ raise Jamf::UnsupportedError, "Deleting #{self} objects is not currently supported" unless self.class.deletable?
403
+ @cnx.delete rsrc_path
404
+ end
405
+
406
+ # Two collection resource objects are the same if their id's are the same
407
+ def <=>(other)
408
+ id <=> other.id
409
+ end
410
+
411
+ # Private Instance Methods
412
+ ############################################
413
+ private
414
+
415
+ def create_in_jamf
416
+ result = @cnx.post self.class.rsrc_path, to_jamf
417
+ @id = result[:id]
418
+ end
419
+
420
+ end # class CollectionResource
421
+
422
+ end # module JAMF