Class: Jamf::AdvancedSearch

Inherits:
APIObject show all
Includes:
Creatable, Criteriable, Sitable, Updatable
Defined in:
lib/jamf/api/classic/base_classes/advanced_search.rb

Overview

A Parent class for Advanced Computer, MobileDevice, and User searchs

Subclasses must define:

  • the constant RESULT_CLASS which is the JSS Module class of the item returned by the search, e.g. Jamf::Computer

  • the constant RESULT_ID_FIELDS, which is an Array of Symbols that come from the API in the search_results along with the symbolized display fields. E.g. for AdvancedComputerSearches, :id, :name, and :udid are present along with whatever display fields have been defined.

Constant Summary collapse

EXPORT_FORMATS =

Class Constants

%i[csv tab xml].freeze
SITE_SUBSET =

Where is site data located in the API JSON?

:top

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**args) ⇒ AdvancedSearch

Returns a new instance of AdvancedSearch.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 146

def initialize(**args)
  super **args

  # @init_data now has the raw data
  # so fill in our attributes or set defaults

  @sql_text = @init_data[:sql_text]
  @site = Jamf::APIObject.get_name(@init_data[:site])

  @display_fields = @init_data[:display_fields] ? @init_data[:display_fields].map { |f| f[:name] } : []

  @search_results = @init_data[self.class::RESULT_CLASS::RSRC_LIST_KEY]
  @search_results ||= []
  @result_display_keys = if @search_results.empty?
                           []
                         else
                           @search_results[0].keys - self.class::RESULT_ID_FIELDS
                         end

  # make sure each hash of the search results
  # has a key matching a standard key.
  #
  # @search_results.each do |hash|
  #   hash.keys.each do |key|
  #     std_key = key.to_s.gsub(':', '').gsub(/ |-/, '_').to_sym
  #     next if hash[std_key]
  #     hash[std_key] = hash[key]
  #   end
  # end
end

Instance Attribute Details

#criteriaJamf::Criteriable::Criteria Originally defined in module Criteriable

Returns the criteria for the instance into which we’re mixed.

Returns:

#display_fieldsArray<String>

The API delivers these as an array of Hashes, where each hash has only one key, :name => the name of the fields/ExtAttrib to display. It should probably not have the underlying Hashes, and just be an array of names. This class converts it to just an Array of field names (Strings) for internal use.

These fields are returned in the @search_results data along with :id, :name, and other unique identifiers for each found item. In that data, their names have colons removed, abd spaces and dashes converted to underscores, and they are symbolized. See attribute result_display_keys

Returns:

  • (Array<String>)

    the fields to be returned with the search results



103
104
105
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 103

def display_fields
  @display_fields
end

#need_to_updateBoolean (readonly) Originally defined in module Updatable

Returns do we have unsaved changes?.

Returns:

  • (Boolean)

    do we have unsaved changes?

#result_display_keysArray<Symbol> (readonly)

The search result Hash keys for the #display_fields of the search

The field names in #display_fields are strings matching how the field is labeled in the web UI (including the names of Extension Attributes). They have to be that way when submitting them to the API, and thats mostly what #display_fields and related methods are for.

However, when those names come back as the Hash Keys of the #search_results they (inconsistently) have spaces and/or dashes converted to underscores, and colons are removed. The JSON module then converts the keys to Symbols, so they don’t match the #display_fields.

For example, the display field “Last Check-in” might come back as any of these Symbols:

  • :“Last Check-in”

  • :Last_Check_in

  • :“Last_Check-in”

Also, the data returned in the #search_results contains more keys than just the #display_fields - namely it comes with some standard identifiers for each found item. such as JSS id number and name.

#result_display_keys will hold just the Hash keys corresponding to the #display_fields by taking the keys from the first result Hash, and removing the identifier keys as listed in each subclass’s RESULT_ID_FIELDS constant.

Returns:



132
133
134
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 132

def result_display_keys
  @result_display_keys
end

#search_resultsArray<Hash> (readonly)

Each Hash is one object that matches the criteria. Within each hash there are variable keys, but always at least the keys defined in each subclasses RESULT_ID_FIELDS

The other keys correspond to the #display_fields defined for this Advanced Search.

Returns:

  • (Array<Hash>)

    the results of the search



87
88
89
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 87

def search_results
  @search_results
end

#siteString (readonly)

Returns the name of the site for this search.

Returns:

  • (String)

    the name of the site for this search



135
136
137
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 135

def site
  @site
end

#sql_textString (readonly)

Returns the SQL query generated by the JSS based on the critera.

Returns:

  • (String)

    the SQL query generated by the JSS based on the critera



138
139
140
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 138

def sql_text
  @sql_text
end

Instance Method Details

#clone(new_name, api: nil, cnx: nil) ⇒ APIObject Originally defined in module Creatable

make a clone of this API object, with a new name. The class must be creatable

Parameters:

  • name (String)

    the name for the new object

  • cnx (Jamf::Connection) (defaults to: nil)

    the API in which to create the object Defaults to the API used to instantiate this object

Returns:

  • (APIObject)

    An unsaved clone of this APIObject with the given name

Raises:

#countInteger

Returns the number of items found by the search.

Returns:

  • (Integer)

    the number of items found by the search



266
267
268
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 266

def count
  @search_results.count
end

#create(get_results = false) ⇒ Integer

Create in the JSS

If get_results is true, they’ll be available in #search_results. This might be slow.

Parameters:

  • get_results (Boolean) (defaults to: false)

    should the results of the search be queried immediately?

Returns:

  • (Integer)

    the id of the newly created search

Raises:



188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 188

def create(get_results = false)
  raise Jamf::InvalidDataError, 'Jamf::Criteriable::Criteria instance required' unless @criteria.is_a? Jamf::Criteriable::Criteria
  raise Jamf::InvalidDataError, 'display_fields must be an Array.' unless @display_fields.is_a? Array

  orig_timeout = @cnx.timeout
  @cnx.timeout = 1800
  super()
  requery_search_results if get_results
  @cnx.timeout = orig_timeout

  @id # remember to return the id
end

#export(output_file, format = :csv, overwrite = false) ⇒ Pathname

Note:

This method only exports the display fields defined in this advanced search for

Export the display fields of the search results to a file.

the search_result members (computers, mobile_devices, or users) It doesn’t currently provide the ability to export subsets of info about those objects, as the Web UI does (e.g. group memberships, applications, receipts, etc)

Parameters:

  • output_file (String, Pathname)

    The file in which to store the exported results

  • format (Symbol) (defaults to: :csv)

    one of :csv, :tab, or :xml, defaults to :csv

  • overwrite (Boolean) (defaults to: false)

    should the output_file be overwrite if it exists? Defaults to false

Returns:

  • (Pathname)

    the path to the output file

Raises:



285
286
287
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
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 285

def export(output_file, format = :csv, overwrite = false)
  raise Jamf::InvalidDataError, "Export format must be one of: :#{EXPORT_FORMATS.join ', :'}" unless EXPORT_FORMATS.include? format

  out = Pathname.new output_file

  unless overwrite
    raise Jamf::AlreadyExistsError, "The output file already exists: #{out}" if out.exist?
  end

  case format
  when :csv
    require 'csv'
    CSV.open(out.to_s, 'wb') do |csv|
      csv << @result_display_keys
      @search_results.each do |row|
        csv << @result_display_keys.map { |key| row[key] }
      end # each do row
    end # CSV.open

  when :tab
    tabbed = @result_display_keys.join("\t") + "\n"
    @search_results.each do |row|
      tabbed << @result_display_keys.map { |key| row[key] }.join("\t") + "\n"
    end # each do row
    out.jss_save tabbed.chomp

  else # :xml
    doc = REXML::Document.new '<?xml version="1.0" encoding="ISO-8859-1"?>'
    members = doc.add_element self.class::RESULT_CLASS::RSRC_LIST_KEY.to_s
    @search_results.each do |row|
      member = members.add_element self.class::RESULT_CLASS::RSRC_OBJECT_KEY.to_s
      @result_display_keys.each do |field|
        member.add_element(field.to_s.tr(' ', '_')).text = row[field].empty? ? nil : row[field]
      end # ech do field
    end # each do row
    out.jss_save doc.to_s.gsub('><', ">\n<")
  end # case

  out
end

#name=(newname) ⇒ void Originally defined in module Updatable

This method returns an undefined value.

Change the name of this item Remember to #update to push changes to the server.

Parameters:

  • newname (String)

    the new name

Raises:

#parse_criteriavoid Originally defined in module Criteriable

This method returns an undefined value.

During initialization, convert the @init_data Hash into a Jamf::Criteriable::Criteria instance stored in @criteria

Classes mixing in this module must call this in #initialize

#requery_search_resultsArray<Hash>

Requery the API for the search results.

This can be very slow, so temporarily reset the API timeout to 30 minutes

Returns:



237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 237

def requery_search_results
  orig_open_timeout = @cnx.open_timeout
  orig_timeout = @cnx.timeout
  @cnx.timeout = 1800
  @cnx.open_timeout = 1800
  begin
    requery = self.class.fetch(id: @id)
    @search_results = requery.search_results
    @result_display_keys = requery.result_display_keys
  ensure
    @cnx.timeout = orig_timeout
    @cnx.open_timeout = orig_open_timeout
  end
end

#save(get_results = false) ⇒ Object

Wrapper/alias for both create and update



220
221
222
223
224
225
226
227
228
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 220

def save(get_results = false)
  if @in_jss
    raise Jamf::UnsupportedError, 'Updating this object in the JSS is currently not supported by ruby-jss' unless updatable?
    update get_results
  else
    raise Jamf::UnsupportedError, 'Creating this object in the JSS is currently not supported by ruby-jss' unless creatable?
    create get_results
  end
end

#should_updatevoid Originally defined in module Criteriable

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Allow our Criteria to tell us when there’s been a change that needs to be updated.

#site=(new_site) ⇒ void Originally defined in module Sitable

This method returns an undefined value.

Change the site of this object. Any of the NON_SITES values will unset the site

Parameters:

  • new_site (Integer, String)

    The new site

Raises:

#site_assigned?Boolean Originally defined in module Sitable

Does this object have a site assigned?

Returns:

  • (Boolean)

    Does this object have a site assigned?

#site_idInteger Originally defined in module Sitable

The id of the site for this object.

Returns:

  • (Integer)

    The id of the site for this object.

#site_nameString Also known as: site Originally defined in module Sitable

The name of the site for this object. For backward compatibility, this is aliased to just ‘site’

Returns:

  • (String)

    The name of the site for this object.

#site_objectJamf::Site Originally defined in module Sitable

The Jamf::Site instance for this object’s site

Returns:

  • (Jamf::Site)

    The Jamf::Site instance for this object’s site

#unset_sitevoid Originally defined in module Sitable

This method returns an undefined value.

Set the site to nothing

#update(get_results = false) ⇒ Integer

Save any changes

If get_results is true, they’ll be available in #search_results. This might be slow.

Parameters:

  • get_results (Boolean) (defaults to: false)

    should the results of the search be queried immediately?

Returns:

  • (Integer)

    the id of the updated search



209
210
211
212
213
214
215
216
217
# File 'lib/jamf/api/classic/base_classes/advanced_search.rb', line 209

def update(get_results = false)
  orig_timeout = @cnx.timeout
  @cnx.timeout = 1800
  super()
  requery_search_results if get_results
  @cnx.timeout = orig_timeout

  @id # remember to return the id
end