ruby-jss 0.7.0 → 0.8.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 +4 -4
- data/CHANGES.md +29 -22
- data/README.md +66 -86
- data/bin/jamfHelperBackgrounder +148 -0
- data/bin/netseg-update +0 -1
- data/lib/jss.rb +20 -9
- data/lib/jss/api_connection.rb +369 -295
- data/lib/jss/api_object.rb +651 -418
- data/lib/jss/api_object/account.rb +69 -77
- data/lib/jss/api_object/advanced_search.rb +201 -236
- data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +42 -42
- data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +33 -43
- data/lib/jss/api_object/advanced_search/advanced_user_search.rb +33 -43
- data/lib/jss/api_object/building.rb +39 -52
- data/lib/jss/api_object/categorizable.rb +221 -0
- data/lib/jss/api_object/category.rb +81 -89
- data/lib/jss/api_object/computer.rb +486 -525
- data/lib/jss/api_object/computer_invitation.rb +73 -86
- data/lib/jss/api_object/criteriable.rb +6 -7
- data/lib/jss/api_object/ebook.rb +21 -0
- data/lib/jss/api_object/extendable.rb +6 -8
- data/lib/jss/api_object/group.rb +0 -3
- data/lib/jss/api_object/locatable.rb +19 -20
- data/lib/jss/api_object/mac_application.rb +21 -0
- data/lib/jss/api_object/mobile_device.rb +30 -21
- data/lib/jss/api_object/mobile_device_application.rb +447 -0
- data/lib/jss/api_object/mobile_device_configuration_profile.rb +21 -0
- data/lib/jss/api_object/osx_configuration_profile.rb +0 -3
- data/lib/jss/api_object/package.rb +21 -34
- data/lib/jss/api_object/peripheral.rb +16 -18
- data/lib/jss/api_object/policy.rb +5 -83
- data/lib/jss/api_object/purchasable.rb +11 -13
- data/lib/jss/api_object/scopable.rb +11 -12
- data/lib/jss/api_object/script.rb +3 -17
- data/lib/jss/api_object/self_servable.rb +419 -205
- data/lib/jss/api_object/self_servable/icon.rb +179 -0
- data/lib/jss/api_object/updatable.rb +35 -34
- data/lib/jss/api_object/uploadable.rb +72 -70
- data/lib/jss/api_object/user.rb +6 -7
- data/lib/jss/api_object/vppable.rb +117 -0
- data/lib/jss/client.rb +264 -225
- data/lib/jss/db_connection.rb +7 -5
- data/lib/jss/exceptions.rb +50 -42
- data/lib/jss/ruby_extensions.rb +8 -7
- data/lib/jss/ruby_extensions/object.rb +19 -0
- data/lib/jss/utility.rb +82 -40
- data/lib/jss/version.rb +1 -1
- metadata +37 -68
- data/bin/jss-webhook-server +0 -3
- data/lib/jss/webhooks.rb +0 -53
- data/lib/jss/webhooks/README.md +0 -269
- data/lib/jss/webhooks/configuration.rb +0 -213
- data/lib/jss/webhooks/data/sample_handlers/RestAPIOperation-executable +0 -91
- data/lib/jss/webhooks/data/sample_handlers/RestAPIOperation.rb +0 -45
- data/lib/jss/webhooks/data/sample_jsons/ComputerAdded.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/ComputerCheckIn.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/ComputerInventoryCompleted.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/ComputerPolicyFinished.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/ComputerPushCapabilityChanged.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/JSSShutdown.json +0 -14
- data/lib/jss/webhooks/data/sample_jsons/JSSStartup.json +0 -14
- data/lib/jss/webhooks/data/sample_jsons/MobileDeviceCheckIn.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/MobileDeviceCommandCompleted.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/MobileDeviceEnrolled.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/MobileDevicePushSent.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/MobileDeviceUnEnrolled.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/PatchSoftwareTitleUpdated.json +0 -14
- data/lib/jss/webhooks/data/sample_jsons/PushSent.json +0 -11
- data/lib/jss/webhooks/data/sample_jsons/RestAPIOperation.json +0 -15
- data/lib/jss/webhooks/data/sample_jsons/SCEPChallenge.json +0 -10
- data/lib/jss/webhooks/data/sample_jsons/SmartGroupComputerMembershipChange.json +0 -13
- data/lib/jss/webhooks/data/sample_jsons/SmartGroupMobileDeviceMembershipChange.json +0 -13
- data/lib/jss/webhooks/event.rb +0 -139
- data/lib/jss/webhooks/event/computer_added.rb +0 -38
- data/lib/jss/webhooks/event/computer_check_in.rb +0 -38
- data/lib/jss/webhooks/event/computer_inventory_completed.rb +0 -38
- data/lib/jss/webhooks/event/computer_policy_finished.rb +0 -38
- data/lib/jss/webhooks/event/computer_push_capability_changed.rb +0 -38
- data/lib/jss/webhooks/event/handlers.rb +0 -192
- data/lib/jss/webhooks/event/jss_shutdown.rb +0 -38
- data/lib/jss/webhooks/event/jss_startup.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_check_in.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_command_completed.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_enrolled.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_push_sent.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_unenrolled.rb +0 -38
- data/lib/jss/webhooks/event/patch_software_title_updated.rb +0 -38
- data/lib/jss/webhooks/event/push_sent.rb +0 -38
- data/lib/jss/webhooks/event/rest_api_operation.rb +0 -38
- data/lib/jss/webhooks/event/scep_challenge.rb +0 -38
- data/lib/jss/webhooks/event/smart_group_computer_membership_change.rb +0 -38
- data/lib/jss/webhooks/event/smart_group_mobile_device_membership_change.rb +0 -38
- data/lib/jss/webhooks/event/webhook.rb +0 -40
- data/lib/jss/webhooks/event_objects.rb +0 -112
- data/lib/jss/webhooks/event_objects/computer.rb +0 -49
- data/lib/jss/webhooks/event_objects/jss.rb +0 -36
- data/lib/jss/webhooks/event_objects/mobile_device.rb +0 -48
- data/lib/jss/webhooks/event_objects/patch_software_title_update.rb +0 -38
- data/lib/jss/webhooks/event_objects/push.rb +0 -33
- data/lib/jss/webhooks/event_objects/rest_api_operation.rb +0 -37
- data/lib/jss/webhooks/event_objects/scep_challenge.rb +0 -32
- data/lib/jss/webhooks/event_objects/smart_group.rb +0 -35
- data/lib/jss/webhooks/server_app.rb +0 -37
- data/lib/jss/webhooks/server_app/routes.rb +0 -27
- data/lib/jss/webhooks/server_app/routes/handle_webhook_event.rb +0 -39
- data/lib/jss/webhooks/server_app/routes/home.rb +0 -37
- data/lib/jss/webhooks/server_app/self_signed_cert.rb +0 -65
- data/lib/jss/webhooks/server_app/server.rb +0 -60
- data/lib/jss/webhooks/version.rb +0 -32
data/lib/jss/api_object.rb
CHANGED
|
@@ -26,139 +26,139 @@
|
|
|
26
26
|
###
|
|
27
27
|
module JSS
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
# Module Variables
|
|
30
30
|
#####################################
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
# Module Methods
|
|
33
33
|
#####################################
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
# Classes
|
|
36
36
|
#####################################
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
38
|
+
# This class is the parent to all JSS API objects. It provides standard methods and structures
|
|
39
|
+
# that apply to all API resouces.
|
|
40
|
+
#
|
|
41
|
+
# See the README.md file for general info about using subclasses of JSS::APIObject
|
|
42
|
+
#
|
|
43
|
+
# == Subclassing
|
|
44
|
+
#
|
|
45
|
+
# === Constructor
|
|
46
|
+
#
|
|
47
|
+
# In general, subclasses should do any class-specific argument checking before
|
|
48
|
+
# calling super, and then afterwards, use the contents of @init_data to populate
|
|
49
|
+
# any class-specific attributes. @id, @name, @rest_rsrc, and @in_jss are handled here.
|
|
50
|
+
#
|
|
51
|
+
# If a subclass can be looked up by some key other than :name or :id, the subclass must
|
|
52
|
+
# pass the keys as an Array in the second argument when calling super from #initialize.
|
|
53
|
+
# See {JSS::Computer#initialize} for an example of how to implement this feature.
|
|
54
|
+
#
|
|
55
|
+
# === Object Creation
|
|
56
|
+
#
|
|
57
|
+
# If a subclass should be able to be created in the JSS be sure to include {JSS::Creatable}
|
|
58
|
+
#
|
|
59
|
+
# The constructor should verify any extra required data (aside from :name) in the args before or after
|
|
60
|
+
# calling super.
|
|
61
|
+
#
|
|
62
|
+
# See {JSS::Creatable} for more details.
|
|
63
|
+
#
|
|
64
|
+
# === Object Modification
|
|
65
|
+
#
|
|
66
|
+
# If a subclass should be modifiable in the JSS, include {JSS::Updatable}, q.v. for details.
|
|
67
|
+
#
|
|
68
|
+
# === Object Deletion
|
|
69
|
+
#
|
|
70
|
+
# All subclasses can be deleted in the JSS.
|
|
71
|
+
#
|
|
72
|
+
# === Required Constants
|
|
73
|
+
#
|
|
74
|
+
# Subclasses *must* provide certain Constants in order to correctly interpret API data and
|
|
75
|
+
# communicate with the API.
|
|
76
|
+
#
|
|
77
|
+
# ==== RSRC_BASE = [String], The base for REST resources of this class
|
|
78
|
+
#
|
|
79
|
+
# e.g. 'computergroups' in "https://casper.mycompany.com:8443/JSSResource/computergroups/id/12"
|
|
80
|
+
#
|
|
81
|
+
# ==== RSRC_LIST_KEY = [Symbol] The Hash key for the JSON list output of all objects of this class in the JSS.
|
|
82
|
+
#
|
|
83
|
+
# e.g. the JSON output of resource "JSSResource/computergroups" is a hash
|
|
84
|
+
# with one item (an Array of computergroups). That item's key is the Symbol :computer_groups
|
|
85
|
+
#
|
|
86
|
+
# ==== RSRC_OBJECT_KEY = [Symbol] The Hash key used for individual JSON object output.
|
|
87
|
+
# It's also used in various error messages
|
|
88
|
+
#
|
|
89
|
+
# e.g. the JSON output of the resource "JSSResource/computergroups/id/436" is
|
|
90
|
+
# a hash with one item (another hash with details of one computergroup).
|
|
91
|
+
# That item's key is the Symbol :computer_group
|
|
92
|
+
#
|
|
93
|
+
# ==== VALID_DATA_KEYS = [Array<Symbol>] The Hash keys used to verify validity of :data
|
|
94
|
+
# When instantiating a subclass using :data => somehash, some minimal checks are performed
|
|
95
|
+
# to ensure the data is valid for the subclass
|
|
96
|
+
#
|
|
97
|
+
# The Symbols in this Array are compared to the keys of the hash provided.
|
|
98
|
+
# If any of these don't exist in the hash's keys, then the :data is
|
|
99
|
+
# not valid and an exception is raised.
|
|
100
|
+
#
|
|
101
|
+
# The keys :id and :name must always exist in the hash.
|
|
102
|
+
# If only :id and :name are valid, VALID_DATA_KEYS should be an empty array.
|
|
103
|
+
#
|
|
104
|
+
# e.g. for a department, only :id and :name are valid, so VALID_DATA_KEYS is an empty Array ([])
|
|
105
|
+
# but for a computer group, the keys :computers and :is_smart must be present as well.
|
|
106
|
+
# so VALID_DATA_KEYS will be [:computers, :is_smart]
|
|
107
|
+
#
|
|
108
|
+
# *NOTE* Some API objects have data broken into subsections, in which case the
|
|
109
|
+
# VALID_DATA_KEYS are expected in the section :general.
|
|
110
|
+
#
|
|
111
111
|
class APIObject
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
# Mix-Ins
|
|
114
114
|
#####################################
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
# Class Variables
|
|
117
117
|
#####################################
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
# This Hash holds the most recent API query for a list of all items in any subclass,
|
|
120
|
+
# keyed by the subclass's RSRC_LIST_KEY. See the self.all class method.
|
|
121
|
+
#
|
|
122
|
+
# When the .all method is called without an argument, and this hash has
|
|
123
|
+
# a matching value, the value is returned, rather than requerying the
|
|
124
|
+
# API. The first time a class calls .all, or whnever refresh is
|
|
125
|
+
# not false, the API is queried and the value in this hash is updated.
|
|
126
|
+
#
|
|
127
127
|
@@all_items = {}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
# Class Methods
|
|
130
130
|
#####################################
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
132
|
+
# Return an Array of Hashes for all objects of this subclass in the JSS.
|
|
133
|
+
#
|
|
134
|
+
# This method is only valid in subclasses of JSS::APIObject, and is
|
|
135
|
+
# the parsed JSON output of an API query for the resource defined in the subclass's RSRC_BASE,
|
|
136
|
+
# e.g. for JSS::Computer, with the RSRC_BASE of :computers,
|
|
137
|
+
# This method retuens the output of the 'JSSResource/computers' resource,
|
|
138
|
+
# which is a list of all computers in the JSS.
|
|
139
|
+
#
|
|
140
|
+
# Each item in the Array is a Hash with at least two keys, :id and :name.
|
|
141
|
+
# The class methods .all_ids and .all_names provide easier access to those data
|
|
142
|
+
# as mapped Arrays.
|
|
143
|
+
#
|
|
144
|
+
# Some API classes provide other data in each Hash, e.g. :udid (for computers
|
|
145
|
+
# and mobile devices) or :is_smart (for groups).
|
|
146
|
+
#
|
|
147
|
+
# Subclasses implementing those API classes should provide .all_xxx
|
|
148
|
+
# class methods for accessing those other values as mapped Arrays,
|
|
149
|
+
# e.g. JSS::Computer.all_udids
|
|
150
|
+
#
|
|
151
|
+
# The results of the first query for each subclass is stored in @@all_items
|
|
152
|
+
# and returned at every future call, so as to not requery the server every time.
|
|
153
|
+
#
|
|
154
|
+
# To force requerying to get updated data, provided a non-false argument.
|
|
155
|
+
# I usually use :refresh, so that it's obvious what I'm doing, but true, 1,
|
|
156
|
+
# or anything besides false or nil will work.
|
|
157
|
+
#
|
|
158
|
+
# @param refresh[Boolean] should the data be re-queried from the API?
|
|
159
|
+
#
|
|
160
|
+
# @return [Array<Hash{:name=>String, :id=> Integer}>]
|
|
161
|
+
#
|
|
162
162
|
def self.all(refresh = false)
|
|
163
163
|
raise JSS::UnsupportedError, '.all can only be called on subclasses of JSS::APIObject' if self == JSS::APIObject
|
|
164
164
|
@@all_items[self::RSRC_LIST_KEY] = nil if refresh
|
|
@@ -166,92 +166,92 @@ module JSS
|
|
|
166
166
|
@@all_items[self::RSRC_LIST_KEY] = JSS::API.get_rsrc(self::RSRC_BASE)[self::RSRC_LIST_KEY]
|
|
167
167
|
end
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
169
|
+
# Returns an Array of the JSS id numbers of all the members
|
|
170
|
+
# of the subclass.
|
|
171
|
+
#
|
|
172
|
+
# e.g. When called from subclass JSS::Computer,
|
|
173
|
+
# returns the id's of all computers in the JSS
|
|
174
|
+
#
|
|
175
|
+
# @param refresh[Boolean] should the data be re-queried from the API?
|
|
176
|
+
#
|
|
177
|
+
# @return [Array<Integer>] the ids of all items of this subclass in the JSS
|
|
178
|
+
#
|
|
179
179
|
def self.all_ids(refresh = false)
|
|
180
180
|
all(refresh).map { |i| i[:id] }
|
|
181
181
|
end
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
183
|
+
# Returns an Array of the JSS names of all the members
|
|
184
|
+
# of the subclass.
|
|
185
|
+
#
|
|
186
|
+
# e.g. When called from subclass JSS::Computer,
|
|
187
|
+
# returns the names of all computers in the JSS
|
|
188
|
+
#
|
|
189
|
+
# @param refresh[Boolean] should the data be re-queried from the API?
|
|
190
|
+
#
|
|
191
|
+
# @return [Array<String>] the names of all item of this subclass in the JSS
|
|
192
|
+
#
|
|
193
193
|
def self.all_names(refresh = false)
|
|
194
194
|
all(refresh).map { |i| i[:name] }
|
|
195
195
|
end
|
|
196
196
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
197
|
+
# Return a hash of all objects of this subclass
|
|
198
|
+
# in the JSS where the key is the id, and the value
|
|
199
|
+
# is some other key in the data items returned by the JSS::APIObject.all.
|
|
200
|
+
#
|
|
201
|
+
# If the other key doesn't exist in the API
|
|
202
|
+
# data, (eg :udid for JSS::Department) the values will be nil.
|
|
203
|
+
#
|
|
204
|
+
# Use this method to map ID numbers to other identifiers returned
|
|
205
|
+
# by the API list resources. Invert its result to map the other
|
|
206
|
+
# identfier to ids.
|
|
207
|
+
#
|
|
208
|
+
# @example
|
|
209
|
+
# JSS::Computer.map_all_ids_to(:name)
|
|
210
|
+
#
|
|
211
|
+
# # Returns, eg {2 => "kimchi", 5 => "mantis"}
|
|
212
|
+
#
|
|
213
|
+
# JSS::Computer.map_all_ids_to(:name).invert
|
|
214
|
+
#
|
|
215
|
+
# # Returns, eg {"kimchi" => 2, "mantis" => 5}
|
|
216
|
+
#
|
|
217
|
+
# @param other_key[Symbol] the other data key with which to associate each id
|
|
218
|
+
#
|
|
219
|
+
# @param refresh[Boolean] should the data re-queried from the API?
|
|
220
|
+
#
|
|
221
|
+
# @return [Hash{Integer => Oject}] the associated ids and data
|
|
222
|
+
#
|
|
223
223
|
def self.map_all_ids_to(other_key, refresh = false)
|
|
224
224
|
h = {}
|
|
225
225
|
all(refresh).each { |i| h[i[:id]] = i[other_key] }
|
|
226
226
|
h
|
|
227
227
|
end
|
|
228
228
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
229
|
+
# Return an Array of JSS::APIObject subclass instances
|
|
230
|
+
# e.g when called on JSS::Package, return all JSS::Package
|
|
231
|
+
# objects in the JSS.
|
|
232
|
+
#
|
|
233
|
+
# NOTE: This may be slow as it has to look up each object individually!
|
|
234
|
+
# use it wisely.
|
|
235
|
+
#
|
|
236
|
+
# @param refresh[Boolean] should the data re-queried from the API?
|
|
237
|
+
#
|
|
238
|
+
# @return [Hash{Integer => Object}] the objects requested
|
|
239
239
|
def self.all_objects(refresh = false)
|
|
240
240
|
objects_key = "#{self::RSRC_LIST_KEY}_objects".to_sym
|
|
241
241
|
@@all_items[objects_key] = nil if refresh
|
|
242
242
|
return @@all_items[objects_key] if @@all_items[objects_key]
|
|
243
|
-
@@all_items[objects_key] = all(refresh
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
243
|
+
@@all_items[objects_key] = all(refresh).map { |o| new id: o[:id] }
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Return true or false if an object of this subclass
|
|
247
|
+
# with the given name or id exists on the server
|
|
248
|
+
#
|
|
249
|
+
# @param identfier [String,Integer] The name or id of object to check for
|
|
250
|
+
#
|
|
251
|
+
# @param refresh [Boolean] Should the data be re-read from the server
|
|
252
|
+
#
|
|
253
|
+
# @return [Boolean] does an object with the given name or id exist?
|
|
254
|
+
#
|
|
255
255
|
def self.exist?(identfier, refresh = false)
|
|
256
256
|
case identfier
|
|
257
257
|
when Integer
|
|
@@ -263,18 +263,18 @@ module JSS
|
|
|
263
263
|
end
|
|
264
264
|
end
|
|
265
265
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
266
|
+
# Return an id or nil if an object of this subclass
|
|
267
|
+
# with the given name or id exists on the server
|
|
268
|
+
#
|
|
269
|
+
# Subclasses may want to override this method to support more
|
|
270
|
+
# identifiers than name and id.
|
|
271
|
+
#
|
|
272
|
+
# @param identfier [String,Integer] The name or id of object to check for
|
|
273
|
+
#
|
|
274
|
+
# @param refresh [Boolean] Should the data be re-read from the server
|
|
275
|
+
#
|
|
276
|
+
# @return [Integer, nil] the id of the matching object, or nil if it doesn't exist
|
|
277
|
+
#
|
|
278
278
|
def self.valid_id(identfier, refresh = false)
|
|
279
279
|
case identfier
|
|
280
280
|
when Integer
|
|
@@ -286,78 +286,77 @@ module JSS
|
|
|
286
286
|
end
|
|
287
287
|
end
|
|
288
288
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
289
|
+
# Convert an Array of Hashes of API object data to a
|
|
290
|
+
# REXML element.
|
|
291
|
+
#
|
|
292
|
+
# Given an Array of Hashes of items in the subclass
|
|
293
|
+
# where each Hash has at least an :id or a :name key,
|
|
294
|
+
# (as what comes from the .all class method)
|
|
295
|
+
# return a REXML <classes> element
|
|
296
|
+
# with one <class> element per Hash member.
|
|
297
|
+
#
|
|
298
|
+
# @example
|
|
299
|
+
# # for class JSS::Computer
|
|
300
|
+
# some_comps = [{:id=>2, :name=>"kimchi"},{:id=>5, :name=>"mantis"}]
|
|
301
|
+
# xml_names = JSS::Computer.xml_list some_comps
|
|
302
|
+
# puts xml_names # output manually formatted for clarity, xml.to_s has no newlines between elements
|
|
303
|
+
#
|
|
304
|
+
# <computers>
|
|
305
|
+
# <computer>
|
|
306
|
+
# <name>kimchi</name>
|
|
307
|
+
# </computer>
|
|
308
|
+
# <computer>
|
|
309
|
+
# <name>mantis</name>
|
|
310
|
+
# </computer>
|
|
311
|
+
# </computers>
|
|
312
|
+
#
|
|
313
|
+
# xml_ids = JSS::Computer.xml_list some_comps, :id
|
|
314
|
+
# puts xml_names # output manually formatted for clarity, xml.to_s has no newlines between elements
|
|
315
|
+
#
|
|
316
|
+
# <computers>
|
|
317
|
+
# <computer>
|
|
318
|
+
# <id>2</id>
|
|
319
|
+
# </computer>
|
|
320
|
+
# <computer>
|
|
321
|
+
# <id>5</id>
|
|
322
|
+
# </computer>
|
|
323
|
+
# </computers>
|
|
324
|
+
#
|
|
325
|
+
# @param array[Array<Hash{:name=>String, :id =>Integer, Symbol=>#to_s}>] the Array of subclass data to convert
|
|
326
|
+
#
|
|
327
|
+
# @param content[Symbol] the Hash key to use as the inner element for each member of the Array
|
|
328
|
+
#
|
|
329
|
+
# @return [REXML::Element] the XML element representing the data
|
|
330
|
+
#
|
|
331
331
|
def self.xml_list(array, content = :name)
|
|
332
332
|
JSS.item_list_to_rexml_list self::RSRC_LIST_KEY, self::RSRC_OBJECT_KEY, array, content
|
|
333
333
|
end
|
|
334
334
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
###
|
|
335
|
+
# Some API objects contain references to other API objects. Usually those
|
|
336
|
+
# references are a Hash containing the :id and :name of the target. Sometimes,
|
|
337
|
+
# however the reference is just the name of the target.
|
|
338
|
+
#
|
|
339
|
+
# A Script has a property :category, which comes from the API as
|
|
340
|
+
# a String, the name of the category for that script. e.g. "GoodStuff"
|
|
341
|
+
#
|
|
342
|
+
# A Policy also has a property :category, but it comes from the API as a Hash
|
|
343
|
+
# with both the name and id, e.g. !{:id => 8, :name => "GoodStuff"}
|
|
344
|
+
#
|
|
345
|
+
# When that reference is to a single thing (like the category to which something belongs)
|
|
346
|
+
# APIObject subclasses usually store only the name, and use the name when
|
|
347
|
+
# returning data to the API.
|
|
348
|
+
#
|
|
349
|
+
# When an object references a list of related objects
|
|
350
|
+
# (like the computers assigned to a user) that list will be and Array of Hashes
|
|
351
|
+
# as above, with both the :id and :name
|
|
352
|
+
#
|
|
353
|
+
# This method is just a handy way to extract the name regardless of how it comes
|
|
354
|
+
# from the API. Most APIObject subclasses use it in their #initialize method
|
|
355
|
+
#
|
|
356
|
+
# @param a_thing[String,Array] the api data from which we're extracting the name
|
|
357
|
+
#
|
|
358
|
+
# @return [String] the name extracted from a_thing
|
|
359
|
+
#
|
|
361
360
|
def self.get_name(a_thing)
|
|
362
361
|
case a_thing
|
|
363
362
|
when String
|
|
@@ -369,194 +368,232 @@ module JSS
|
|
|
369
368
|
end
|
|
370
369
|
end
|
|
371
370
|
|
|
371
|
+
# Retrieve an object from the API.
|
|
372
|
+
#
|
|
373
|
+
# This is the preferred way to retrieve existing objects from the JSS.
|
|
374
|
+
# It's a wrapper for using APIObject.new
|
|
375
|
+
# and avoids the confusion of using ruby's .new class method when you're not
|
|
376
|
+
# creating a new object.
|
|
377
|
+
#
|
|
378
|
+
# For creating new objects in the JSS, use {APIObject.make}
|
|
379
|
+
#
|
|
380
|
+
# @param args[Hash] The data for fetching an object, such as id: or name:
|
|
381
|
+
# See {APIObject#initialize}
|
|
382
|
+
#
|
|
383
|
+
# @return [APIObject] The ruby-instance of a JSS object
|
|
384
|
+
#
|
|
385
|
+
def self.fetch(**args)
|
|
386
|
+
raise JSS::UnsupportedError, 'JSS::APIObject cannot be instantiated' if self.class == JSS::APIObject
|
|
387
|
+
raise ArgumentError, 'Use .create to create new JSS objects' if args[:id] == :new
|
|
388
|
+
new args
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Make a ruby instance of a not-yet-existing APIObject.
|
|
392
|
+
#
|
|
393
|
+
# This is the preferred way to create new objects in the JSS.
|
|
394
|
+
# It's a wrapper for using APIObject.new with the 'id: :new' parameter.
|
|
395
|
+
# and helps avoid the confusion of using ruby's .new class method for making
|
|
396
|
+
# ruby instances.
|
|
397
|
+
#
|
|
398
|
+
# For retrieving existing objects in the JSS, use {APIObject.fetch}
|
|
399
|
+
#
|
|
400
|
+
# For actually creating the object in the JSS, see {APIObject#create}
|
|
401
|
+
#
|
|
402
|
+
# @param args[Hash] The data for creating an object, such as name:
|
|
403
|
+
# See {APIObject#initialize}
|
|
404
|
+
#
|
|
405
|
+
# @return [APIObject] The un-created ruby-instance of a JSS object
|
|
406
|
+
#
|
|
407
|
+
def self.make(**args)
|
|
408
|
+
raise JSS::UnsupportedError, 'JSS::APIObject cannot be instantiated' if self.class == JSS::APIObject
|
|
409
|
+
raise ArgumentError, "Use '#{self.class}.fetch id: xx' to retrieve existing JSS objects" if args[:id]
|
|
410
|
+
args[:id] = :new
|
|
411
|
+
new args
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
|
|
372
415
|
### Class Constants
|
|
373
416
|
#####################################
|
|
374
417
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
418
|
+
# These Symbols are added to VALID_DATA_KEYS for performing the
|
|
419
|
+
# :data validity test described above.
|
|
420
|
+
#
|
|
378
421
|
REQUIRED_DATA_KEYS = [:id, :name].freeze
|
|
379
422
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
423
|
+
# By default, these keys are available for object lookups
|
|
424
|
+
# Others can be added by subclasses using an array of them
|
|
425
|
+
# as the second argument to super(initialize)
|
|
426
|
+
# The keys must be Symbols that match the keyname in the resource url.
|
|
427
|
+
# e.g. :serialnumber for JSSResource/computers/serialnumber/xxxxx
|
|
428
|
+
#
|
|
386
429
|
DEFAULT_LOOKUP_KEYS = [:id, :name].freeze
|
|
387
430
|
|
|
388
|
-
|
|
431
|
+
# Attributes
|
|
389
432
|
#####################################
|
|
390
433
|
|
|
391
|
-
|
|
434
|
+
# @return [Integer] the JSS id number
|
|
392
435
|
attr_reader :id
|
|
393
436
|
|
|
394
|
-
|
|
437
|
+
# @return [String] the name
|
|
395
438
|
attr_reader :name
|
|
396
439
|
|
|
397
|
-
|
|
440
|
+
# @return [Boolean] is it in the JSS?
|
|
398
441
|
attr_reader :in_jss
|
|
399
442
|
|
|
400
|
-
|
|
443
|
+
# @return [String] the Rest resource for API access (the part after "JSSResource/" )
|
|
401
444
|
attr_reader :rest_rsrc
|
|
402
445
|
|
|
403
|
-
|
|
446
|
+
# Constructor
|
|
404
447
|
#####################################
|
|
405
448
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
449
|
+
# The args hash must include :id, :name, or :data.
|
|
450
|
+
# * :id or :name will be looked up via the API
|
|
451
|
+
# * * if the subclass includes JSS::Creatable, :id can be :new, to create a new object in the JSS.
|
|
452
|
+
# and :name is required
|
|
453
|
+
# * :data must be the JSON output of a separate {JSS::APIConnection} query (a Hash of valid object data)
|
|
454
|
+
#
|
|
455
|
+
# Some subclasses can accept other options, by pasing their keys in a final Array
|
|
456
|
+
#
|
|
457
|
+
# @param args[Hash] the data for looking up, or constructing, a new object.
|
|
458
|
+
#
|
|
459
|
+
# @option args :id[Integer] the jss id to look up
|
|
460
|
+
#
|
|
461
|
+
# @option args :name[String] the name to look up
|
|
462
|
+
#
|
|
463
|
+
# @option args :data[Hash] the JSON output of a separate {JSS::APIConnection} query
|
|
464
|
+
#
|
|
465
|
+
# @param other_lookup_keys[Array<Symbol>] Hash keys other than :id and :name, by which an API
|
|
466
|
+
# lookup may be performed.
|
|
467
|
+
#
|
|
425
468
|
def initialize(args = {}, other_lookup_keys = [])
|
|
469
|
+
args[:other_lookup_keys] ||= other_lookup_keys
|
|
470
|
+
|
|
471
|
+
raise JSS::UnsupportedError, 'JSS::APIObject cannot be instantiated' if self.class == JSS::APIObject
|
|
472
|
+
|
|
473
|
+
### what lookup key are we using, if any?
|
|
474
|
+
lookup_keys = DEFAULT_LOOKUP_KEYS
|
|
475
|
+
lookup_keys += self.class::OTHER_LOOKUP_KEYS if defined? self.class::OTHER_LOOKUP_KEYS
|
|
476
|
+
lookup_key = (lookup_keys & args.keys)[0]
|
|
426
477
|
|
|
427
478
|
####### Previously looked-up JSON data
|
|
479
|
+
# DEPRECATED: pre-lookedup data is never used
|
|
480
|
+
# and support for it will be going away.
|
|
428
481
|
if args[:data]
|
|
429
482
|
|
|
430
483
|
@init_data = args[:data]
|
|
431
484
|
|
|
432
|
-
|
|
433
|
-
@got_subsets = @init_data[:general].is_a?(Hash)
|
|
434
|
-
|
|
435
|
-
### data must include all they keys in REQUIRED_DATA_KEYS + VALID_DATA_KEYS
|
|
436
|
-
### in either the main hash keys or the :general sub-hash, if it exists
|
|
437
|
-
hash_to_check = @got_subsets ? @init_data[:general] : @init_data
|
|
438
|
-
combined_valid_keys = self.class::REQUIRED_DATA_KEYS + self.class::VALID_DATA_KEYS
|
|
439
|
-
keys_ok = (hash_to_check.keys & combined_valid_keys).count == combined_valid_keys.count
|
|
440
|
-
unless keys_ok
|
|
441
|
-
raise(
|
|
442
|
-
JSS::InvalidDataError,
|
|
443
|
-
":data is not valid JSON for a #{self.class::RSRC_OBJECT_KEY} from the API. It needs at least the keys :#{combined_valid_keys.join ', :'}"
|
|
444
|
-
)
|
|
445
|
-
end
|
|
446
|
-
|
|
447
|
-
### and the id must be in the jss
|
|
448
|
-
raise NoSuchItemError, "No #{self.class::RSRC_OBJECT_KEY} with JSS id: #{@init_data[:id]}" unless \
|
|
449
|
-
self.class.all_ids.include? hash_to_check[:id]
|
|
485
|
+
validate_external_init_data
|
|
450
486
|
|
|
451
487
|
###### Make a new one in the JSS, but only if we've included the Creatable module
|
|
452
488
|
elsif args[:id] == :new
|
|
453
489
|
|
|
454
|
-
|
|
455
|
-
|
|
490
|
+
validate_init_for_creation(args)
|
|
491
|
+
setup_object_for_creation(args)
|
|
492
|
+
return
|
|
456
493
|
|
|
457
|
-
|
|
458
|
-
|
|
494
|
+
###### Look up the data via the API
|
|
495
|
+
else
|
|
496
|
+
@init_data = look_up_object_data(args)
|
|
497
|
+
end ## end arg parsing
|
|
459
498
|
|
|
460
|
-
|
|
461
|
-
|
|
499
|
+
parse_init_data
|
|
500
|
+
@need_to_update = false
|
|
501
|
+
end # init
|
|
462
502
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
@name = args[:name]
|
|
466
|
-
@init_data = { name: args[:name] }
|
|
467
|
-
@in_jss = false
|
|
468
|
-
@rest_rsrc = "#{self.class::RSRC_BASE}/name/#{CGI.escape @name}"
|
|
469
|
-
@need_to_update = true
|
|
470
|
-
return
|
|
503
|
+
# Public Instance Methods
|
|
504
|
+
#####################################
|
|
471
505
|
|
|
472
|
-
|
|
506
|
+
# Either Create or Update this object in the JSS
|
|
507
|
+
#
|
|
508
|
+
# If this item is creatable or updatable, then
|
|
509
|
+
# create it if needed, or update it if it already exists.
|
|
510
|
+
#
|
|
511
|
+
# @return [Integer] the id of the item created or updated
|
|
512
|
+
#
|
|
513
|
+
def save
|
|
514
|
+
if @in_jss
|
|
515
|
+
raise JSS::UnsupportedError, 'Updating this object in the JSS is currently not supported' unless updatable?
|
|
516
|
+
update
|
|
473
517
|
else
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
518
|
+
raise JSS::UnsupportedError, 'Creating this object in the JSS is currently not supported' unless creatable?
|
|
519
|
+
create
|
|
520
|
+
end
|
|
521
|
+
end
|
|
477
522
|
|
|
478
|
-
|
|
523
|
+
# Mix-in Modules.
|
|
524
|
+
# Each module made for mixing in to APIObject subclasses
|
|
525
|
+
# sets an appropriate constant to true.
|
|
526
|
+
# These methods provide a simple way to programattically determine
|
|
527
|
+
# if an object has one of the mixed-in modules available.
|
|
479
528
|
|
|
480
|
-
|
|
529
|
+
# @return [Boolean] See {JSS::Creatable}
|
|
530
|
+
def creatable?
|
|
531
|
+
defined? self.class::CREATABLE
|
|
532
|
+
end
|
|
481
533
|
|
|
482
|
-
|
|
483
|
-
|
|
534
|
+
# @return [Boolean] See {JSS::Updatable}
|
|
535
|
+
def updatable?
|
|
536
|
+
defined? self.class::UPDATABLE
|
|
537
|
+
end
|
|
484
538
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
@name = lookup_key == :name ? args[lookup_key] : @init_data[:name]
|
|
539
|
+
# @return [Boolean] See {JSS::Categorizable}
|
|
540
|
+
def categorizable?
|
|
541
|
+
defined? self.class::CATEGORIZABLE
|
|
542
|
+
end
|
|
490
543
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
544
|
+
# @return [Boolean] See {JSS::VPPable}
|
|
545
|
+
def vppable?
|
|
546
|
+
defined? self.class::VPPABLE
|
|
547
|
+
end
|
|
495
548
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
# like ldap servers, which have them in :connection
|
|
501
|
-
# Whereever both :id and :name are, that's the main subset
|
|
502
|
-
|
|
503
|
-
@init_data.keys.each do |subset|
|
|
504
|
-
@main_subset = @init_data[subset] if @init_data[subset].is_a?(Hash) && @init_data[subset][:id] && @init_data[subset][:name]
|
|
505
|
-
break if @main_subset
|
|
506
|
-
end
|
|
507
|
-
@main_subset ||= @init_data
|
|
549
|
+
# @return [Boolean] See {JSS::SelfServable}
|
|
550
|
+
def self_servable?
|
|
551
|
+
defined? self.class::SELF_SERVABLE
|
|
552
|
+
end
|
|
508
553
|
|
|
509
|
-
|
|
510
|
-
|
|
554
|
+
# @return [Boolean] See {JSS::criteriable}
|
|
555
|
+
def criterable?
|
|
556
|
+
defined? self.class::CRITERIABLE
|
|
557
|
+
end
|
|
511
558
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
559
|
+
# @return [Boolean] See {JSS::extendable}
|
|
560
|
+
def extendable?
|
|
561
|
+
defined? self.class::EXTENDABLE
|
|
562
|
+
end
|
|
516
563
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
564
|
+
# @return [Boolean] See {JSS::Matchable}
|
|
565
|
+
def matchable?
|
|
566
|
+
defined? self.class::MATCHABLE
|
|
567
|
+
end
|
|
521
568
|
|
|
522
|
-
|
|
523
|
-
|
|
569
|
+
# @return [Boolean] See {JSS::Locatable}
|
|
570
|
+
def locatable?
|
|
571
|
+
defined? self.class::LOCATABLE
|
|
572
|
+
end
|
|
524
573
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
end
|
|
574
|
+
# @return [Boolean] See {JSS::Purchasable}
|
|
575
|
+
def purchasable?
|
|
576
|
+
defined? self.class::PURCHASABLE
|
|
577
|
+
end
|
|
529
578
|
|
|
530
|
-
|
|
531
|
-
|
|
579
|
+
# @return [Boolean] See {JSS::Scopable}
|
|
580
|
+
def scopable?
|
|
581
|
+
defined? self.class::SCOPABLE
|
|
582
|
+
end
|
|
532
583
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
### create it if needed, or update it if it already exists.
|
|
537
|
-
###
|
|
538
|
-
### @return [Integer] the id of the item created or updated
|
|
539
|
-
###
|
|
540
|
-
def save
|
|
541
|
-
if @in_jss
|
|
542
|
-
raise JSS::UnsupportedError, 'Updating this object in the JSS is currently not supported' \
|
|
543
|
-
unless defined? self.class::UPDATABLE
|
|
544
|
-
update
|
|
545
|
-
else
|
|
546
|
-
raise JSS::UnsupportedError, 'Creating this object in the JSS is currently not supported' \
|
|
547
|
-
unless defined? self.class::CREATABLE
|
|
548
|
-
create
|
|
549
|
-
end
|
|
584
|
+
# @return [Boolean] See {JSS::Uploadable}
|
|
585
|
+
def uploadable?
|
|
586
|
+
defined? self.class::UPLOADABLE
|
|
550
587
|
end
|
|
551
588
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
589
|
+
# Delete this item from the JSS.
|
|
590
|
+
#
|
|
591
|
+
# Subclasses may want to redefine this method,
|
|
592
|
+
# first calling super, then setting other attributes to
|
|
593
|
+
# nil, false, empty, etc..
|
|
594
|
+
#
|
|
595
|
+
# @return [void]
|
|
596
|
+
#
|
|
560
597
|
def delete
|
|
561
598
|
return nil unless @in_jss
|
|
562
599
|
JSS::API.delete_rsrc @rest_rsrc
|
|
@@ -567,34 +604,224 @@ module JSS
|
|
|
567
604
|
:deleted
|
|
568
605
|
end # delete
|
|
569
606
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
###
|
|
607
|
+
# A meaningful string representation of this object
|
|
608
|
+
#
|
|
609
|
+
# @return [String]
|
|
610
|
+
#
|
|
575
611
|
def to_s
|
|
576
612
|
"#{self.class}, name: #{@name}, id: #{@id}"
|
|
577
613
|
end
|
|
578
614
|
|
|
579
|
-
|
|
580
|
-
### Private Instance Methods
|
|
615
|
+
# Private Instance Methods
|
|
581
616
|
#####################################
|
|
582
617
|
private
|
|
583
618
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
619
|
+
# If we were passed pre-lookedup API data, validate it,
|
|
620
|
+
# raising exceptions if not valid.
|
|
621
|
+
#
|
|
622
|
+
# DEPRECATED: pre-lookedup data is never used
|
|
623
|
+
# and support for it will be going away.
|
|
624
|
+
#
|
|
625
|
+
# @return [void]
|
|
626
|
+
#
|
|
627
|
+
def validate_external_init_data
|
|
628
|
+
# data must include all they keys in REQUIRED_DATA_KEYS + VALID_DATA_KEYS
|
|
629
|
+
# in either the main hash keys or the :general sub-hash, if it exists
|
|
630
|
+
hash_to_check = @init_data[:general] ? @init_data[:general] : @init_data
|
|
631
|
+
combined_valid_keys = self.class::REQUIRED_DATA_KEYS + self.class::VALID_DATA_KEYS
|
|
632
|
+
keys_ok = (hash_to_check.keys & combined_valid_keys).count == combined_valid_keys.count
|
|
633
|
+
unless keys_ok
|
|
634
|
+
raise(
|
|
635
|
+
JSS::InvalidDataError,
|
|
636
|
+
":data is not valid JSON for a #{self.class::RSRC_OBJECT_KEY} from the API. It needs at least the keys :#{combined_valid_keys.join ', :'}"
|
|
637
|
+
)
|
|
638
|
+
end
|
|
639
|
+
# and the id must be in the jss
|
|
640
|
+
raise NoSuchItemError, "No #{self.class::RSRC_OBJECT_KEY} with JSS id: #{@init_data[:id]}" unless \
|
|
641
|
+
self.class.all_ids.include? hash_to_check[:id]
|
|
642
|
+
end # validate_init_data
|
|
643
|
+
|
|
644
|
+
# If we're making a new object in the JSS, make sure we were given
|
|
645
|
+
# valid data to do so, raise exceptions otherwise.
|
|
646
|
+
#
|
|
647
|
+
# NOTE: some subclasses may do further validation.
|
|
648
|
+
#
|
|
649
|
+
# TODO: support for objects that can have duplicate names.
|
|
650
|
+
#
|
|
651
|
+
# @param args[Hash] The args passed to #initialize
|
|
652
|
+
#
|
|
653
|
+
# @return [void]
|
|
654
|
+
#
|
|
655
|
+
def validate_init_for_creation(args)
|
|
656
|
+
raise JSS::UnsupportedError, "Creating #{self.class::RSRC_LIST_KEY} isn't yet supported. Please use other Casper workflows." unless creatable?
|
|
657
|
+
|
|
658
|
+
raise JSS::MissingDataError, "You must provide a :name to create a #{self.class::RSRC_OBJECT_KEY}." unless args[:name]
|
|
659
|
+
|
|
660
|
+
raise JSS::AlreadyExistsError, "A #{self.class::RSRC_OBJECT_KEY} already exists with the name '#{args[:name]}'" if self.class.all_names.include? args[:name]
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
# Given initialization args, perform an API lookup for an object.
|
|
664
|
+
#
|
|
665
|
+
# @param args[Hash] The args passed to #initialize
|
|
666
|
+
#
|
|
667
|
+
# @return [Hash] The parsed JSON data for the object from the API
|
|
668
|
+
#
|
|
669
|
+
def look_up_object_data(args)
|
|
670
|
+
# what lookup key are we using?
|
|
671
|
+
combined_lookup_keys = self.class::DEFAULT_LOOKUP_KEYS + args[:other_lookup_keys]
|
|
672
|
+
lookup_key = (combined_lookup_keys & args.keys)[0]
|
|
673
|
+
|
|
674
|
+
raise JSS::MissingDataError, "Args must include a lookup key, one of: :#{combined_lookup_keys.join(', :')}" unless lookup_key
|
|
675
|
+
|
|
676
|
+
rsrc = "#{self.class::RSRC_BASE}/#{lookup_key}/#{args[lookup_key]}"
|
|
677
|
+
|
|
678
|
+
return JSS::API.get_rsrc(rsrc)[self.class::RSRC_OBJECT_KEY]
|
|
679
|
+
rescue RestClient::ResourceNotFound
|
|
680
|
+
raise NoSuchItemError, "No #{self.class::RSRC_OBJECT_KEY} found matching: #{lookup_key}/#{args[lookup_key]}"
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
# Start examining the @init_data recieved from the API
|
|
684
|
+
#
|
|
685
|
+
# @return [void]
|
|
686
|
+
#
|
|
687
|
+
def parse_init_data
|
|
688
|
+
# set empty strings to nil
|
|
689
|
+
@init_data.jss_nillify! '', :recurse
|
|
690
|
+
|
|
691
|
+
# Find the "main" subset which contains :id and :name
|
|
692
|
+
@main_subset = find_main_subset
|
|
693
|
+
|
|
694
|
+
@id = @main_subset[:id]
|
|
695
|
+
@name = @main_subset[:name]
|
|
696
|
+
@in_jss = true
|
|
697
|
+
@rest_rsrc = "#{self.class::RSRC_BASE}/id/#{@id}"
|
|
698
|
+
|
|
699
|
+
# many things have a :site
|
|
700
|
+
# TODO: Implement a Sitable mixin module
|
|
701
|
+
@site = JSS::APIObject.get_name(@main_subset[:site]) if @main_subset[:site]
|
|
702
|
+
|
|
703
|
+
##### Handle Mix-ins
|
|
704
|
+
initialize_category
|
|
705
|
+
initialize_location
|
|
706
|
+
initialize_purchasing
|
|
707
|
+
initialize_scope
|
|
708
|
+
initialize_criteria
|
|
709
|
+
initialize_ext_attrs
|
|
710
|
+
initialize_vpp
|
|
711
|
+
initialize_self_service
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
# Find which part of the @init_data contains the :id and :name
|
|
715
|
+
#
|
|
716
|
+
# If they aren't at the top-level of the init hash they are in a subset hash,
|
|
717
|
+
# usually :general, but sometimes someething else,
|
|
718
|
+
# like ldap servers, which have them in :connection
|
|
719
|
+
# Whereever both :id and :name are, that's the main subset
|
|
720
|
+
#
|
|
721
|
+
# @return [Hash] The part of the @init_data containg the :id and :name
|
|
722
|
+
#
|
|
723
|
+
def find_main_subset
|
|
724
|
+
@init_data.each do |key, value|
|
|
725
|
+
next unless value.is_a? Hash
|
|
726
|
+
return value if value.keys.include?(:id) && value.keys.include?(:name)
|
|
727
|
+
end
|
|
728
|
+
@init_data
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
# parse category data during initialization
|
|
732
|
+
#
|
|
733
|
+
# @return [void]
|
|
734
|
+
#
|
|
735
|
+
def initialize_category
|
|
736
|
+
parse_category if categorizable?
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
# parse location data during initialization
|
|
740
|
+
#
|
|
741
|
+
# @return [void]
|
|
742
|
+
#
|
|
743
|
+
def initialize_location
|
|
744
|
+
parse_location if locatable?
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
# parse purchasing data during initialization
|
|
748
|
+
#
|
|
749
|
+
# @return [void]
|
|
750
|
+
#
|
|
751
|
+
def initialize_purchasing
|
|
752
|
+
parse_purchasing if purchasable?
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
# parse scope data during initialization
|
|
756
|
+
#
|
|
757
|
+
# @return [void]
|
|
758
|
+
#
|
|
759
|
+
def initialize_scope
|
|
760
|
+
parse_scope if scopable?
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
# parse criteria data during initialization
|
|
764
|
+
#
|
|
765
|
+
# @return [void]
|
|
766
|
+
#
|
|
767
|
+
def initialize_criteria
|
|
768
|
+
parse_criteria if criterable?
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
# parse ext_attrs data during initialization
|
|
772
|
+
#
|
|
773
|
+
# @return [void]
|
|
774
|
+
#
|
|
775
|
+
def initialize_ext_attrs
|
|
776
|
+
parse_ext_attrs if extendable?
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
# parse vpp data during initialization
|
|
780
|
+
#
|
|
781
|
+
# @return [void]
|
|
782
|
+
#
|
|
783
|
+
def initialize_vpp
|
|
784
|
+
parse_vpp if vppable?
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
# parse self_service data during initialization
|
|
788
|
+
#
|
|
789
|
+
# @return [void]
|
|
790
|
+
#
|
|
791
|
+
def initialize_self_service
|
|
792
|
+
parse_self_service if self_servable?
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
# Set the basics for creating a new object in the JSS
|
|
796
|
+
#
|
|
797
|
+
# @param args[Type] describe_args
|
|
798
|
+
#
|
|
799
|
+
# @return [Type] description_of_returned_object
|
|
800
|
+
#
|
|
801
|
+
def setup_object_for_creation(args)
|
|
802
|
+
# NOTE: subclasses may want to pre-populate more keys in @init_data when :id == :new
|
|
803
|
+
# then parse them into attributes later.
|
|
804
|
+
@init_data = { name: args[:name] }
|
|
805
|
+
@name = args[:name]
|
|
806
|
+
@in_jss = false
|
|
807
|
+
@rest_rsrc = "#{self.class::RSRC_BASE}/name/#{CGI.escape @name}"
|
|
808
|
+
@need_to_update = true
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
# Return a String with the XML Resource
|
|
812
|
+
# for submitting creation or changes to the JSS via
|
|
813
|
+
# the API via the Creatable or Updatable modules
|
|
814
|
+
#
|
|
815
|
+
# Most classes will redefine this method.
|
|
816
|
+
#
|
|
590
817
|
def rest_xml
|
|
591
|
-
doc = REXML::Document.new APIConnection::XML_HEADER
|
|
818
|
+
doc = REXML::Document.new JSS::APIConnection::XML_HEADER
|
|
592
819
|
tmpl = doc.add_element self.class::RSRC_OBJECT_KEY.to_s
|
|
593
820
|
tmpl.add_element('name').text = @name
|
|
594
821
|
doc.to_s
|
|
595
822
|
end
|
|
596
823
|
|
|
597
|
-
|
|
824
|
+
# Aliases
|
|
598
825
|
|
|
599
826
|
alias in_jss? in_jss
|
|
600
827
|
|
|
@@ -611,6 +838,8 @@ require 'jss/api_object/purchasable'
|
|
|
611
838
|
require 'jss/api_object/updatable'
|
|
612
839
|
require 'jss/api_object/extendable'
|
|
613
840
|
require 'jss/api_object/self_servable'
|
|
841
|
+
require 'jss/api_object/categorizable'
|
|
842
|
+
require 'jss/api_object/vppable'
|
|
614
843
|
|
|
615
844
|
### Mix-in Sub Modules with Classes
|
|
616
845
|
require 'jss/api_object/criteriable'
|
|
@@ -629,8 +858,12 @@ require 'jss/api_object/computer'
|
|
|
629
858
|
require 'jss/api_object/computer_invitation'
|
|
630
859
|
require 'jss/api_object/department'
|
|
631
860
|
require 'jss/api_object/distribution_point'
|
|
861
|
+
require 'jss/api_object/ebook'
|
|
632
862
|
require 'jss/api_object/ldap_server'
|
|
863
|
+
require 'jss/api_object/mac_application'
|
|
633
864
|
require 'jss/api_object/mobile_device'
|
|
865
|
+
require 'jss/api_object/mobile_device_application'
|
|
866
|
+
require 'jss/api_object/mobile_device_configuration_profile'
|
|
634
867
|
require 'jss/api_object/netboot_server'
|
|
635
868
|
require 'jss/api_object/network_segment'
|
|
636
869
|
require 'jss/api_object/osx_configuration_profile'
|