ruby-jss 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ruby-jss might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGES.md +23 -0
- data/lib/jss/api_connection.rb +20 -13
- data/lib/jss/api_object.rb +105 -1
- data/lib/jss/api_object/extension_attribute.rb +165 -68
- data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +176 -282
- data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +66 -171
- data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +51 -92
- data/lib/jss/api_object/management_history.rb +29 -0
- data/lib/jss/db_connection.rb +1 -0
- data/lib/jss/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83836b3e036658c6254365b47fe0d2b00b03dd3e75e42cd80f27ba29988d6b3b
|
4
|
+
data.tar.gz: 2e5b73fd7fd6f76f474170cc40165a156b79e37e96807fcfad0ee987e5df8018
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbf7ba2137f3de2a8aaff77c8c53f84086913f6ee154345d3419e94e874422116405d04ab1448c254a09e1375a734738050f07738d860245dc629f8a157c96d8
|
7
|
+
data.tar.gz: 4480768a24e0cd1372f35bafcce1d2effe646e09da4ee44bf195deff2451f46d946c94c8c34aa0ecb74dd5177ad274f4c7f9c7e0c60abf1fe0da55b1271d0b00
|
data/CHANGES.md
CHANGED
@@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## \[1.2.2] - 2019-10-31
|
8
|
+
### Added
|
9
|
+
- the ManagementHistory mixin module used by the Computer and MobileDevice classes, now has a `last_mdm_contact` class and instance method, which returns a Time object for the timestamp of the most recent completed MDM command. This is useful for MobileDevices, which don't have anything like the `last_checkin` value for comptuers, indicating real communication between the device and Jamf Pro.
|
10
|
+
Note that the `last_inventory_update` value does NOT indicate such communication, since that timestamp is updated when values are changed via the API
|
11
|
+
|
12
|
+
- All APIObject Subclasses (Policy, Computer, MobileDevice, ComputerGroup, etc..) now have `get_raw`, `post_raw` & `put_raw` class methods, which are simpler wrappers for APIConnection#get_rsrc, #post_rsrc, and #put_rsrc.
|
13
|
+
- `get_raw` takes an object's id, and returns the 'raw' JSON (parsed into a ruby Hash with symbolized keys) or a REXML::Document (from which you'll probably want to use the `root` element). If you pass `as_string: true` you'll get the un-parsed JSON or XML string directly from the API
|
14
|
+
This can be useful when you need to retrieve the full object, to get some data not available in the summary-list, but instantiating the full ruby class is too slow.
|
15
|
+
- `post_raw` & `put_raw` can send raw XML to the API without instantiating objects. In some cases, where you're making simple changes to simple XML, this can be faster than fetching a full instance and the re-saving it.
|
16
|
+
WARNING You must create or acquire the XML to be sent, and no validation will be performed on it. It must be a String of XML, or something that returns such a string with #to_s, such as a REXML::Document, or a REXML::Element.
|
17
|
+
|
18
|
+
- APIConnection#get_rsrc now takes the boolean raw_json: parameter (defaults to false). If true, the raw JSON string is
|
19
|
+
returned, not parsed into a Hash. When requesting XML, it already comes as a string.
|
20
|
+
|
21
|
+
- ExtensionAttribute#attribute_mapping getter & setter for EAs that have the 'LDAP Attribute Mapping' input type.
|
22
|
+
|
23
|
+
### Fixed
|
24
|
+
- DB_CNX.valid_server? now specifies utf8 charset, needed for newer versions of mysql.
|
25
|
+
|
26
|
+
### Changed
|
27
|
+
- Cleaned up and modernized ExtensionAttribute and its subclasses. Marked a few things as deprecated: recon_display, scripting_language, and platform, all in ComputerExtensionAttribute.
|
28
|
+
- Better error message when using `APIObject.fetch :random` on a subclass with no objects
|
29
|
+
|
7
30
|
## \[1.2.0] - 2019-10-17
|
8
31
|
### Added
|
9
32
|
- APIConnection#flushcache can be used to flush all cached data, or just for specific APIObject lists or ExtensionAttribute definitions. This is now used more often throughout ruby-jss.
|
data/lib/jss/api_connection.rb
CHANGED
@@ -327,6 +327,9 @@ module JSS
|
|
327
327
|
# These classes are extendable, and may need cache flushing for EA definitions
|
328
328
|
EXTENDABLE_CLASSES = [JSS::Computer, JSS::MobileDevice, JSS::User].freeze
|
329
329
|
|
330
|
+
# values for the format param of get_rsrc
|
331
|
+
GET_FORMATS = %i[json xml].freeze
|
332
|
+
|
330
333
|
# Attributes
|
331
334
|
#####################################
|
332
335
|
|
@@ -546,36 +549,40 @@ module JSS
|
|
546
549
|
# after the 'JSSResource/' ) The resource must be properly URL escaped
|
547
550
|
# beforehand. Note: URL.encode is deprecated, use CGI.escape
|
548
551
|
#
|
549
|
-
# By default we get the data in JSON, and parse it
|
550
|
-
# into a ruby data structure (arrays, hashes, strings, etc)
|
552
|
+
# By default we get the data in JSON, and parse it into a ruby Hash
|
551
553
|
# with symbolized Hash keys.
|
552
554
|
#
|
555
|
+
# If the second parameter is :xml then the XML version is retrieved and
|
556
|
+
# returned as a String.
|
557
|
+
#
|
558
|
+
# To get the raw JSON string as it comes from the API, pass raw_json: true
|
559
|
+
#
|
553
560
|
# @param rsrc[String] the resource to get
|
554
561
|
# (the part of the API url after the 'JSSResource/' )
|
555
562
|
#
|
556
563
|
# @param format[Symbol] either ;json or :xml
|
557
|
-
#
|
564
|
+
# If the second argument is :xml, the XML data is returned as a String.
|
565
|
+
#
|
566
|
+
# @param raw_json[Boolean] When GETting JSON, return the raw unparsed string
|
567
|
+
# (the XML is always returned as a raw string)
|
558
568
|
#
|
559
569
|
# @return [Hash,String] the result of the get
|
560
570
|
#
|
561
|
-
def get_rsrc(rsrc, format = :json)
|
562
|
-
# puts object_id
|
571
|
+
def get_rsrc(rsrc, format = :json, raw_json: false)
|
563
572
|
validate_connected
|
564
|
-
|
565
|
-
raise JSS::InvalidDataError, 'format must be :json or :xml' unless %i[json xml].include? format
|
573
|
+
raise JSS::InvalidDataError, 'format must be :json or :xml' unless GET_FORMATS.include? format
|
566
574
|
|
567
575
|
begin
|
568
576
|
@last_http_response = @cnx[rsrc].get(accept: format)
|
577
|
+
return JSON.parse(@last_http_response.body, symbolize_names: true) if format == :json && !raw_json
|
578
|
+
|
569
579
|
@last_http_response.body
|
570
580
|
rescue RestClient::ExceptionWithResponse => e
|
571
581
|
handle_http_error e
|
572
582
|
end
|
573
|
-
# TODO: make sure we're returning the String version of the
|
574
|
-
# response (i.e. its body) here and in POST, PUT, DELETE.
|
575
|
-
format == :json ? JSON.parse(@last_http_response, symbolize_names: true) : @last_http_response
|
576
583
|
end
|
577
584
|
|
578
|
-
#
|
585
|
+
# Update an existing JSS resource
|
579
586
|
#
|
580
587
|
# @param rsrc[String] the API resource being changed, the URL part after 'JSSResource/'
|
581
588
|
#
|
@@ -1219,7 +1226,7 @@ module JSS
|
|
1219
1226
|
raise exception
|
1220
1227
|
when RestClient::Conflict
|
1221
1228
|
err = JSS::ConflictError
|
1222
|
-
msg_matcher = /<p>Error:(
|
1229
|
+
msg_matcher = /<p>Error:(.*?)(<|$)/m
|
1223
1230
|
when RestClient::BadRequest
|
1224
1231
|
err = JSS::BadRequestError
|
1225
1232
|
msg_matcher = %r{>Bad Request</p>\n<p>(.*?)</p>\n<p>You can get technical detail}m
|
@@ -1227,7 +1234,7 @@ module JSS
|
|
1227
1234
|
raise
|
1228
1235
|
else
|
1229
1236
|
err = JSS::APIRequestError
|
1230
|
-
msg_matcher = %r{<body.*?>(
|
1237
|
+
msg_matcher = %r{<body.*?>(.*?)</body>}m
|
1231
1238
|
end
|
1232
1239
|
exception.http_body =~ msg_matcher
|
1233
1240
|
msg = Regexp.last_match(1)
|
data/lib/jss/api_object.rb
CHANGED
@@ -809,7 +809,12 @@ module JSS
|
|
809
809
|
end
|
810
810
|
|
811
811
|
# a random object?
|
812
|
-
|
812
|
+
if searchterm == :random
|
813
|
+
rnd_thing = all.sample
|
814
|
+
raise JSS::NoSuchItemError, "No #{self::RSRC_LIST_KEY} found" unless rnd_thing
|
815
|
+
|
816
|
+
return new id: rnd_thing[:id], api: api
|
817
|
+
end
|
813
818
|
|
814
819
|
# get the lookup key and value, if given
|
815
820
|
fetch_key, fetch_val = args.to_a.first
|
@@ -851,6 +856,105 @@ module JSS
|
|
851
856
|
end
|
852
857
|
end # fetch
|
853
858
|
|
859
|
+
# Fetch the mostly- or fully-raw JSON or XML data for an object of this
|
860
|
+
# subclass.
|
861
|
+
#
|
862
|
+
# By default, returns the JSON data parsed into a Hash.
|
863
|
+
#
|
864
|
+
# When format: is anything but :json, returns the XML data parsed into
|
865
|
+
# a REXML::Document
|
866
|
+
#
|
867
|
+
# When as_string: is truthy, returns an unparsed JSON String (or XML String
|
868
|
+
# if format: is not :json) as it comes directly from the API.
|
869
|
+
#
|
870
|
+
# When fetching raw JSON, the returned Hash will have its keys symbolized.
|
871
|
+
#
|
872
|
+
# This can be substantialy faster than instantiating, especially when you don't need
|
873
|
+
# all the ruby goodness of a full instance, but just want a few values for
|
874
|
+
# an object that aren't available in the `all` data
|
875
|
+
#
|
876
|
+
# This is really just a wrapper around {APIConnection.get_rsrc} that
|
877
|
+
# automatically fills in the RSRC::BASE value for you.
|
878
|
+
#
|
879
|
+
# @param id [Integer] the id of the object to fetch
|
880
|
+
#
|
881
|
+
# @param format[Symbol] :json or :xml, defaults to :json
|
882
|
+
#
|
883
|
+
# @param as_string[Boolean] return the raw JSON or XML string as it comes
|
884
|
+
# from the API, do not parse into a Hash or REXML::Document
|
885
|
+
#
|
886
|
+
# @param api[JSS::APIConnection] the connection thru which to fetch this
|
887
|
+
# object. Defaults to the deault API connection in JSS.api
|
888
|
+
#
|
889
|
+
# @return [Hash, REXML::Document, String] the raw data for the object
|
890
|
+
#
|
891
|
+
def self.get_raw(id, format: :json, as_string: false, api: JSS.api)
|
892
|
+
validate_not_metaclass(self)
|
893
|
+
rsrc = "#{self::RSRC_BASE}/id/#{id}"
|
894
|
+
data = api.get_rsrc rsrc, format, raw_json: as_string
|
895
|
+
return data if format == :json || as_string
|
896
|
+
|
897
|
+
REXML::Document.new(data)
|
898
|
+
rescue RestClient::NotFound
|
899
|
+
raise JSS::NoSuchItemError, "No #{self} with id #{id}"
|
900
|
+
end
|
901
|
+
|
902
|
+
# PUT some raw XML to the API for a given id in this subclass.
|
903
|
+
#
|
904
|
+
# WARNING: You must create or acquire the XML to be sent, and no validation
|
905
|
+
# will be performed on it. It must be a String, or something that returns
|
906
|
+
# an XML string with #to_s, such as a REXML::Document, or
|
907
|
+
# a REXML::Element.
|
908
|
+
#
|
909
|
+
# In some cases, where you're making simple changes to simple XML,
|
910
|
+
# this can be faster than fetching a full instance and the re-saving it.
|
911
|
+
#
|
912
|
+
# This is really just a wrapper around {APIConnection.put_rsrc} that
|
913
|
+
# automatically fills in the RSRC::BASE value for you.
|
914
|
+
#
|
915
|
+
# @param id [Integer] the id of the object to PUT
|
916
|
+
#
|
917
|
+
# @param xml [String, #to_s] The XML to send
|
918
|
+
#
|
919
|
+
# @param api[JSS::APIConnection] the connection thru which to fetch this
|
920
|
+
# object. Defaults to the deault API connection in JSS.api
|
921
|
+
#
|
922
|
+
# @return [REXML::Document] the XML response from the API
|
923
|
+
#
|
924
|
+
def self.put_raw(id, xml, api: JSS.api)
|
925
|
+
validate_not_metaclass(self)
|
926
|
+
rsrc = "#{self::RSRC_BASE}/id/#{id}"
|
927
|
+
REXML::Document.new(api.put_rsrc rsrc, xml.to_s)
|
928
|
+
rescue RestClient::NotFound
|
929
|
+
raise JSS::NoSuchItemError, "No #{self} with id #{id}"
|
930
|
+
end
|
931
|
+
|
932
|
+
# POST some raw XML to the API for a given id in this subclass.
|
933
|
+
#
|
934
|
+
# WARNING: You must create or acquire the XML to be sent, and no validation
|
935
|
+
# will be performed on it. It must be a String, or something that returns
|
936
|
+
# an XML string with #to_s, such as a REXML::Document, or
|
937
|
+
# a REXML::Element.
|
938
|
+
#
|
939
|
+
# This probably isn't as much of a speed gain as get_raw or put_raw, as
|
940
|
+
# opposed to instantiating a ruby object, but might still be useful.
|
941
|
+
#
|
942
|
+
# This is really just a wrapper around {APIConnection.post_rsrc} that
|
943
|
+
# automatically fills in the RSRC::BASE value for you.
|
944
|
+
#
|
945
|
+
# @param xml [String, #to_s] The XML to send
|
946
|
+
#
|
947
|
+
# @param api[JSS::APIConnection] the connection thru which to fetch this
|
948
|
+
# object. Defaults to the deault API connection in JSS.api
|
949
|
+
#
|
950
|
+
# @return [REXML::Document] the XML response from the API
|
951
|
+
#
|
952
|
+
def self.post_raw( xml, api: JSS.api)
|
953
|
+
validate_not_metaclass(self)
|
954
|
+
rsrc = "#{self::RSRC_BASE}/id/-1"
|
955
|
+
REXML::Document.new(api.post_rsrc rsrc, xml.to_s)
|
956
|
+
end
|
957
|
+
|
854
958
|
# Make a ruby instance of a not-yet-existing APIObject.
|
855
959
|
#
|
856
960
|
# This is how to create new objects in the JSS. A name: must be provided,
|
@@ -20,10 +20,7 @@
|
|
20
20
|
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
21
|
# KIND, either express or implied. See the Apache License for the specific
|
22
22
|
# language governing permissions and limitations under the Apache License.
|
23
|
-
#
|
24
|
-
#
|
25
23
|
|
26
|
-
#
|
27
24
|
module JSS
|
28
25
|
|
29
26
|
# Classes
|
@@ -89,20 +86,33 @@ module JSS
|
|
89
86
|
INPUT_TYPE_SCRIPT = 'script'.freeze
|
90
87
|
INPUT_TYPE_LDAP = 'LDAP Attribute Mapping'.freeze
|
91
88
|
|
92
|
-
INPUT_TYPES = [
|
89
|
+
INPUT_TYPES = [
|
90
|
+
INPUT_TYPE_FIELD,
|
91
|
+
INPUT_TYPE_POPUP,
|
92
|
+
INPUT_TYPE_SCRIPT,
|
93
|
+
INPUT_TYPE_LDAP
|
94
|
+
].freeze
|
95
|
+
|
93
96
|
DEFAULT_INPUT_TYPE = INPUT_TYPE_FIELD
|
94
97
|
|
95
98
|
# Where can it be displayed in the WebApp?
|
96
|
-
|
99
|
+
WEB_DISPLAY_CHOICE_GENERAL = 'General'.freeze
|
100
|
+
WEB_DISPLAY_CHOICE_OS = 'Operating System'.freeze
|
101
|
+
WEB_DISPLAY_CHOICE_HW = 'Hardware'.freeze
|
102
|
+
WEB_DISPLAY_CHOICE_USER_LOC = 'User and Location'.freeze
|
103
|
+
WEB_DISPLAY_CHOICE_PURCHASING = 'Purchasing'.freeze
|
104
|
+
WEB_DISPLAY_CHOICE_EAS = 'Extension Attributes'.freeze
|
105
|
+
|
97
106
|
WEB_DISPLAY_CHOICES = [
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
107
|
+
WEB_DISPLAY_CHOICE_GENERAL,
|
108
|
+
WEB_DISPLAY_CHOICE_OS,
|
109
|
+
WEB_DISPLAY_CHOICE_HW,
|
110
|
+
WEB_DISPLAY_CHOICE_USER_LOC,
|
111
|
+
WEB_DISPLAY_CHOICE_PURCHASING,
|
112
|
+
WEB_DISPLAY_CHOICE_EAS
|
104
113
|
].freeze
|
105
|
-
|
114
|
+
|
115
|
+
DEFAULT_WEB_DISPLAY_CHOICE = WEB_DISPLAY_CHOICE_EAS
|
106
116
|
|
107
117
|
LAST_RECON_FIELD = 'Last Inventory Update'.freeze
|
108
118
|
LAST_RECON_FIELD_SYM = LAST_RECON_FIELD.tr(' ', '_').to_sym
|
@@ -117,6 +127,7 @@ module JSS
|
|
117
127
|
|
118
128
|
# @return [String] description of the ext attrib
|
119
129
|
attr_reader :description
|
130
|
+
alias desc description
|
120
131
|
|
121
132
|
# @return [String] the type of data created by the EA. Must be one of DATA_TYPES
|
122
133
|
attr_reader :data_type
|
@@ -127,14 +138,15 @@ module JSS
|
|
127
138
|
# @return [Array<String>] the choices available in the UI when the @input_type is "Pop-up Menu"
|
128
139
|
attr_reader :popup_choices
|
129
140
|
|
141
|
+
# @return [String] the LDAP attribute for the User's ldap entry that maps to this EA, when input type is INPUT_TYPE_LDAP
|
142
|
+
attr_reader :attribute_mapping
|
143
|
+
|
130
144
|
# @return [String] In which part of the web UI does the data appear?
|
131
145
|
attr_reader :web_display
|
132
146
|
|
133
|
-
|
134
147
|
# Constructor
|
135
148
|
###################################
|
136
149
|
|
137
|
-
|
138
150
|
# @see JSS::APIObject#initialize
|
139
151
|
#
|
140
152
|
def initialize(args = {})
|
@@ -142,19 +154,30 @@ module JSS
|
|
142
154
|
|
143
155
|
# @init_data now has the raw data
|
144
156
|
# so fill in our attributes or set defaults
|
145
|
-
|
146
157
|
@description = @init_data[:description]
|
147
158
|
@data_type = @init_data[:data_type] || DEFAULT_DATA_TYPE
|
148
|
-
@web_display = @init_data[:inventory_display] || DEFAULT_WEB_DISPLAY_CHOICE
|
149
159
|
|
150
160
|
if @init_data[:input_type]
|
151
|
-
@input_type = @init_data[:input_type][:type]
|
161
|
+
@input_type = @init_data[:input_type][:type]
|
162
|
+
|
163
|
+
@script = @init_data[:input_type][:script]
|
164
|
+
|
165
|
+
@attribute_mapping = @init_data[:input_type][:attribute_mapping]
|
152
166
|
@popup_choices = @init_data[:input_type][:popup_choices]
|
153
167
|
# popups can always contain blank
|
154
168
|
@popup_choices << JSS::BLANK if @popup_choices
|
155
|
-
|
156
|
-
|
169
|
+
|
170
|
+
# These two are deprecated - windows won't be supported for long
|
171
|
+
@platform = @init_data[:input_type][:platform]
|
172
|
+
@scripting_language = @init_data[:input_type][:scripting_language]
|
157
173
|
end
|
174
|
+
@input_type ||= DEFAULT_INPUT_TYPE
|
175
|
+
|
176
|
+
@enabled = @init_data[:enabled]
|
177
|
+
|
178
|
+
@web_display = @init_data[:inventory_display] || DEFAULT_WEB_DISPLAY_CHOICE
|
179
|
+
# deprecated - no longer in the UI
|
180
|
+
@recon_display = @init_data[:recon_display] || @web_display
|
158
181
|
|
159
182
|
# the name of the EA might have spaces and caps, which the will come to us as symbols with the spaces
|
160
183
|
# as underscores, like this.
|
@@ -167,19 +190,16 @@ module JSS
|
|
167
190
|
# @see JSS::Creatable#create
|
168
191
|
#
|
169
192
|
def create
|
170
|
-
|
171
|
-
raise MissingDataError, 'No popup_choices set for Pop-up Menu input_type.' unless @popup_choices.is_a?(Array) && !@popup_choices.empty?
|
172
|
-
end
|
193
|
+
validate_for_save
|
173
194
|
super
|
174
195
|
end
|
175
196
|
|
176
197
|
# @see JSS::Updatable#update
|
177
198
|
#
|
178
199
|
def update
|
179
|
-
|
180
|
-
raise MissingDataError, 'No popup_choices set for Pop-up Menu input_type.' unless @popup_choices.is_a?(Array) && !@popup_choices.empty?
|
181
|
-
end
|
200
|
+
validate_for_save
|
182
201
|
super
|
202
|
+
# this flushes the cached EA itself, used for validating ea values.
|
183
203
|
@api.flushcache self.class
|
184
204
|
end
|
185
205
|
|
@@ -222,10 +242,12 @@ module JSS
|
|
222
242
|
# @return [void]
|
223
243
|
#
|
224
244
|
def description=(new_val)
|
225
|
-
|
245
|
+
new_val = new_val.to_s
|
246
|
+
return if @description == new_val
|
247
|
+
|
226
248
|
@description = new_val
|
227
249
|
@need_to_update = true
|
228
|
-
end #
|
250
|
+
end # name=(newname)
|
229
251
|
|
230
252
|
# Change the data type of this EA
|
231
253
|
#
|
@@ -234,24 +256,28 @@ module JSS
|
|
234
256
|
# @return [void]
|
235
257
|
#
|
236
258
|
def data_type=(new_val)
|
237
|
-
return
|
259
|
+
return if @data_type == new_val
|
238
260
|
raise JSS::InvalidDataError, "data_type must be a string, one of: '#{DATA_TYPES.join("', '")}'" unless DATA_TYPES.include? new_val
|
261
|
+
|
239
262
|
@data_type = new_val
|
240
263
|
@need_to_update = true
|
241
|
-
end
|
264
|
+
end
|
242
265
|
|
243
266
|
# Change the inventory_display of this EA
|
244
267
|
#
|
245
|
-
# @param new_val[String] the new value, which must be a member of
|
268
|
+
# @param new_val[String] the new value, which must be a member of WEB_DISPLAY_CHOICES
|
246
269
|
#
|
247
270
|
# @return [void]
|
248
271
|
#
|
249
272
|
def web_display=(new_val)
|
250
|
-
return
|
251
|
-
|
273
|
+
return if @web_display == new_val
|
274
|
+
unless WEB_DISPLAY_CHOICES.include? new_val
|
275
|
+
raise JSS::InvalidDataError, "inventory_display must be a string, one of: #{WEB_DISPLAY_CHOICES.join(', ')}"
|
276
|
+
end
|
277
|
+
|
252
278
|
@web_display = new_val
|
253
279
|
@need_to_update = true
|
254
|
-
end
|
280
|
+
end
|
255
281
|
|
256
282
|
# Change the input type of this EA
|
257
283
|
#
|
@@ -260,17 +286,39 @@ module JSS
|
|
260
286
|
# @return [void]
|
261
287
|
#
|
262
288
|
def input_type=(new_val)
|
263
|
-
return
|
289
|
+
return if @input_type == new_val
|
264
290
|
raise JSS::InvalidDataError, "input_type must be a string, one of: #{INPUT_TYPES.join(', ')}" unless INPUT_TYPES.include? new_val
|
291
|
+
|
265
292
|
@input_type = new_val
|
266
|
-
|
293
|
+
case @input_type
|
294
|
+
when INPUT_TYPE_FIELD
|
295
|
+
@script = nil
|
296
|
+
@scripting_language = nil
|
297
|
+
@platform = nil
|
298
|
+
@popup_choices = nil
|
299
|
+
@attribute_mapping = nil
|
300
|
+
when INPUT_TYPE_POPUP
|
301
|
+
@script = nil
|
302
|
+
@scripting_language = nil
|
303
|
+
@platform = nil
|
304
|
+
@attribute_mapping = nil
|
305
|
+
when INPUT_TYPE_SCRIPT
|
306
|
+
@popup_choices = nil
|
307
|
+
@attribute_mapping = nil
|
308
|
+
when INPUT_TYPE_LDAP
|
309
|
+
@script = nil
|
310
|
+
@scripting_language = nil
|
311
|
+
@platform = nil
|
312
|
+
@popup_choices = nil
|
313
|
+
end # case
|
314
|
+
|
267
315
|
@need_to_update = true
|
268
|
-
end
|
316
|
+
end
|
269
317
|
|
270
318
|
# Change the Popup Choices of this EA
|
271
319
|
# New value must be an Array, the items will be converted to Strings.
|
272
320
|
#
|
273
|
-
# This automatically sets input_type to
|
321
|
+
# This automatically sets input_type to INPUT_TYPE_POPUP
|
274
322
|
#
|
275
323
|
# Values are checked to ensure they match the @data_type
|
276
324
|
# Note, Dates must be in the format "YYYY-MM-DD hh:mm:ss"
|
@@ -280,7 +328,7 @@ module JSS
|
|
280
328
|
# @return [void]
|
281
329
|
#
|
282
330
|
def popup_choices=(new_val)
|
283
|
-
return
|
331
|
+
return if @popup_choices == new_val
|
284
332
|
raise JSS::InvalidDataError, 'popup_choices must be an Array' unless new_val.is_a?(Array)
|
285
333
|
|
286
334
|
# convert each one to a String,
|
@@ -295,10 +343,29 @@ module JSS
|
|
295
343
|
end
|
296
344
|
v
|
297
345
|
end
|
346
|
+
|
298
347
|
self.input_type = INPUT_TYPE_POPUP
|
299
348
|
@popup_choices = new_val
|
300
349
|
@need_to_update = true
|
301
|
-
end
|
350
|
+
end
|
351
|
+
|
352
|
+
# Change the LDAP Attribute Mapping of this EA
|
353
|
+
# New value must be a String, or respond correctly to #to_s
|
354
|
+
#
|
355
|
+
# This automatically sets input_type to INPUT_TYPE_LDAP
|
356
|
+
#
|
357
|
+
# @param new_val[String, #to_s] the new value
|
358
|
+
#
|
359
|
+
# @return [void]
|
360
|
+
#
|
361
|
+
def attribute_mapping=(new_mapping)
|
362
|
+
new_mapping = JSS::Validate.non_empty_string new_mapping.to_s
|
363
|
+
return if new_mapping == @attribute_mapping
|
364
|
+
|
365
|
+
self.input_type = INPUT_TYPE_LDAP
|
366
|
+
@attribute_mapping = new_mapping
|
367
|
+
@need_to_update = true
|
368
|
+
end
|
302
369
|
|
303
370
|
# Get an Array of Hashes for all inventory objects
|
304
371
|
# with a desired result in their latest report for this EA.
|
@@ -322,7 +389,10 @@ module JSS
|
|
322
389
|
#
|
323
390
|
def all_with_result(search_type, desired_value)
|
324
391
|
raise JSS::NoSuchItemError, "EA Not In JSS! Use #create to create this #{self.class::RSRC_OBJECT_KEY}." unless @in_jss
|
325
|
-
|
392
|
+
unless JSS::Criteriable::Criterion::SEARCH_TYPES.include? search_type.to_s
|
393
|
+
raise JSS::InvalidDataError, 'Invalid search_type, see JSS::Criteriable::Criterion::SEARCH_TYPES'
|
394
|
+
end
|
395
|
+
|
326
396
|
begin
|
327
397
|
search_class = self.class::TARGET_CLASS::SEARCH_CLASS
|
328
398
|
acs = search_class.make api: @api, name: "ruby-jss-EA-result-search-#{Time.now.to_jss_epoch}"
|
@@ -335,13 +405,14 @@ module JSS
|
|
335
405
|
results = []
|
336
406
|
|
337
407
|
acs.search_results.each do |i|
|
338
|
-
value =
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
408
|
+
value =
|
409
|
+
case @data_type
|
410
|
+
when 'Date' then JSS.parse_datetime i[@symbolized_name]
|
411
|
+
when 'Integer' then i[@symbolized_name].to_i
|
412
|
+
else i[@symbolized_name]
|
413
|
+
end # case
|
343
414
|
results << { id: i[:id], name: i[:name], value: value }
|
344
|
-
end
|
415
|
+
end # each
|
345
416
|
ensure
|
346
417
|
acs.delete if acs.is_a? self.class::TARGET_CLASS::SEARCH_CLASS
|
347
418
|
end
|
@@ -375,6 +446,7 @@ module JSS
|
|
375
446
|
#
|
376
447
|
def latest_values
|
377
448
|
raise JSS::NoSuchItemError, "EA Not In JSS! Use #create to create this #{self.class::RSRC_OBJECT_KEY}." unless @in_jss
|
449
|
+
|
378
450
|
tmp_advsrch = "ruby-jss-EA-latest-search-#{Time.now.to_jss_epoch}"
|
379
451
|
|
380
452
|
begin
|
@@ -391,11 +463,12 @@ module JSS
|
|
391
463
|
results = []
|
392
464
|
|
393
465
|
acs.search_results.each do |i|
|
394
|
-
value =
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
466
|
+
value =
|
467
|
+
case @data_type
|
468
|
+
when 'Date' then JSS.parse_datetime i[@symbolized_name]
|
469
|
+
when 'Integer' then i[@symbolized_name].to_i
|
470
|
+
else i[@symbolized_name]
|
471
|
+
end # case
|
399
472
|
|
400
473
|
as_of = Time.parse(i[LAST_RECON_FIELD_SYM]) if i[LAST_RECON_FIELD_SYM] != ''
|
401
474
|
|
@@ -404,42 +477,66 @@ module JSS
|
|
404
477
|
ensure
|
405
478
|
if defined? acs
|
406
479
|
acs.delete if acs
|
407
|
-
|
408
|
-
search_class.fetch(name: tmp_advsrch, api: @api).delete
|
480
|
+
elsif search_class.all_names(:refresh, api: @api).include? tmp_advsrch
|
481
|
+
search_class.fetch(name: tmp_advsrch, api: @api).delete
|
409
482
|
end
|
410
483
|
end
|
411
484
|
|
412
485
|
results
|
413
486
|
end
|
414
487
|
|
415
|
-
# aliases
|
416
|
-
|
417
|
-
alias desc description
|
418
|
-
|
419
488
|
# Private Instance Methods
|
420
489
|
###################
|
421
490
|
|
422
491
|
private
|
423
492
|
|
424
|
-
#
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
493
|
+
# make sure things are OK for saving to Jamf
|
494
|
+
def validate_for_save
|
495
|
+
case @input_type
|
496
|
+
when INPUT_TYPE_POPUP
|
497
|
+
raise MissingDataError, "No popup_choices set for input type: #{INPUT_TYPE_POPUP}" unless @popup_choices.is_a?(Array) && !@popup_choices.empty?
|
498
|
+
when INPUT_TYPE_LDAP
|
499
|
+
raise MissingDataError, "No attribute_mapping set for input type: #{INPUT_TYPE_LDAP}" if @attribute_mapping.to_s.empty?
|
500
|
+
when INPUT_TYPE_SCRIPT
|
501
|
+
raise MissingDataError, "No script set for input_type: #{INPUT_TYPE_SCRIPT}" unless @script
|
502
|
+
|
503
|
+
# Next two lines DEPRECATED
|
504
|
+
@platform ||= 'Mac'
|
505
|
+
raise MissingDataError, "No scripting_language set for Windows '#{INPUT_TYPE_SCRIPT}' input_type." if @platform == 'Windows' && !@scripting_language
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
# Return a REXML doc string for this ext attr, with the current values.
|
510
|
+
def rest_xml
|
430
511
|
ea = REXML::Element.new self.class::RSRC_OBJECT_KEY.to_s
|
431
512
|
ea.add_element('name').text = @name
|
432
|
-
ea.add_element('description').text = @description
|
513
|
+
ea.add_element('description').text = @description if @description
|
433
514
|
ea.add_element('data_type').text = @data_type
|
434
|
-
|
515
|
+
|
516
|
+
unless self.class == JSS::UserExtensionAttribute
|
517
|
+
ea.add_element('inventory_display').text = @web_display if @web_display
|
518
|
+
ea.add_element('recon_display').text = @recon_display if @recon_display
|
519
|
+
end
|
435
520
|
|
436
521
|
it = ea.add_element('input_type')
|
437
522
|
it.add_element('type').text = @input_type
|
438
|
-
|
523
|
+
|
524
|
+
case @input_type
|
525
|
+
when INPUT_TYPE_POPUP
|
439
526
|
pcs = it.add_element('popup_choices')
|
440
|
-
@popup_choices.each { |pc| pcs.add_element('choice').text = pc }
|
527
|
+
@popup_choices.each { |pc| pcs.add_element('choice').text = pc } if @popup_choices.is_a? Array
|
528
|
+
when INPUT_TYPE_LDAP
|
529
|
+
it.add_element('attribute_mapping').text = @attribute_mapping
|
530
|
+
when INPUT_TYPE_SCRIPT
|
531
|
+
ea.add_element('enabled').text = @enabled ? 'true' : 'false'
|
532
|
+
it.add_element('script').text = @script
|
533
|
+
it.add_element('platform').text = @platform || 'Mac'
|
534
|
+
it.add_element('scripting_language').text = @scripting_language if @scripting_language
|
441
535
|
end
|
442
|
-
|
536
|
+
|
537
|
+
doc = REXML::Document.new APIConnection::XML_HEADER
|
538
|
+
doc << ea
|
539
|
+
doc.to_s
|
443
540
|
end # rest xml
|
444
541
|
|
445
542
|
end # class ExtAttrib
|