lib/jss/api_object/advanced_search.rb in ruby-jss-0.7.0 vs lib/jss/api_object/advanced_search.rb in ruby-jss-0.8.1
- old
+ new
@@ -1,370 +1,336 @@
### Copyright 2017 Pixar
-###
+###
### Licensed under the Apache License, Version 2.0 (the "Apache License")
### with the following modification; you may not use this file except in
### compliance with the Apache License and the following modification to it:
### Section 6. Trademarks. is deleted and replaced with:
-###
+###
### 6. Trademarks. This License does not grant permission to use the trade
### names, trademarks, service marks, or product names of the Licensor
### and its affiliates, except as required to comply with Section 4(c) of
### the License and to reproduce the content of the NOTICE file.
-###
+###
### You may obtain a copy of the Apache License at
-###
+###
### http://www.apache.org/licenses/LICENSE-2.0
-###
+###
### Unless required by applicable law or agreed to in writing, software
### distributed under the Apache License with the above modification is
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
### KIND, either express or implied. See the Apache License for the specific
### language governing permissions and limitations under the Apache License.
-###
###
+###
###
module JSS
+ # Module Variables
#####################################
- ### Module Variables
- #####################################
+ # Module Methods
#####################################
- ### Module Methods
- #####################################
+ # Classes
#####################################
- ### Classes
- #####################################
- ###
- ### 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. JSS::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.
- ###
- ###
- ### @see JSS::AdvancedComputerSearch
- ### @see JSS::AdvancedMobileDeviceSearch
- ### @see JSS::AdvancedUserSearch
- ### @see JSS::APIObject
- ###
+ #
+ # 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. JSS::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.
+ #
+ #
+ # @see JSS::AdvancedComputerSearch
+ # @see JSS::AdvancedMobileDeviceSearch
+ # @see JSS::AdvancedUserSearch
+ # @see JSS::APIObject
+ #
class AdvancedSearch < JSS::APIObject
+ # Mix-Ins
#####################################
- ### Mix-Ins
- #####################################
include JSS::Creatable
include JSS::Updatable
include JSS::Criteriable
+ # Class Constants
#####################################
- ### Class Constants
- #####################################
- EXPORT_FORMATS = [:csv, :tab, :xml]
+ EXPORT_FORMATS = [:csv, :tab, :xml].freeze
+ # Attributes
#####################################
- ### Attributes
- #####################################
-
- ###
- ### @return [Array<Hash>] the results of the search
- ###
- ### 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 {AdvancedSearch#display_fields} defined for this
- ### Advanced Search.
- ###
+ #
+ # @return [Array<Hash>] the results of the search
+ #
+ # 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 {AdvancedSearch#display_fields} defined for this
+ # Advanced Search.
+ #
attr_reader :search_results
- ### @return [Array<Symbol>]
- ###
- ### 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,
- ### the JSON module 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.
- ###
+ # @return [Array<Symbol>]
+ #
+ # 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,
+ # the JSON module 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.
+ #
attr_reader :result_display_keys
- ### @return [String] the name of the site for this search
+ # @return [String] the name of the site for this search
attr_reader :site
- ### @return [String] the SQL query generated by the JSS based on the critera
+ # @return [String] the SQL query generated by the JSS based on the critera
attr_reader :sql_text
+ # Constructor
#####################################
- ### Constructor
- #####################################
- ###
- ### @see APIObject#initialize
- ###
+ #
+ # @see APIObject#initialize
+ #
def initialize(args = {})
-
super args
- ### @init_data now has the raw data
- ### so fill in our attributes or set defaults
+ # @init_data now has the raw data
+ # so fill in our attributes or set defaults
@sql_text = @init_data[:sql_text]
@site = JSS::APIObject.get_name(@init_data[:site])
+ @display_fields = @init_data[:display_fields] ? @init_data[:display_fields].map { |f| f[:name] } : []
-
- @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 = @init_data[self.class::RESULT_CLASS::RSRC_LIST_KEY]
@search_results ||= []
- if @search_results.empty?
- @result_display_keys =[]
- else
- @result_display_keys = @search_results[0].keys - self.class::RESULT_ID_FIELDS
- end
+ @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(/ |-/,"_").to_sym
+ std_key = key.to_s.gsub(/ |-/, '_').to_sym
next if hash[std_key]
hash[std_key] = hash[key]
end
end
-
- parse_criteria
-
-
end # init
+ # Public Instance Methods
#####################################
- ### Public Instance Methods
- #####################################
- ###
- ### Create in the JSS
- ###
- ### If get_results is true, they'll be available in {#search_results}. This might be slow.
- ###
- ### @param get_results[Boolean] should the results of the search be queried immediately?
- ###
- ### @return [Integer] the id of the newly created search
- ###
+ # Create in the JSS
+ #
+ # If get_results is true, they'll be available in {#search_results}. This might be slow.
+ #
+ # @param get_results[Boolean] should the results of the search be queried immediately?
+ #
+ # @return [Integer] the id of the newly created search
+ #
def create(get_results = false)
- raise JSS::InvalidDataError, "JSS::Criteriable::Criteria instance required" unless @criteria.kind_of? JSS::Criteriable::Criteria
- raise JSS::InvalidDataError, "display_fields must be an Array." unless @display_fields.kind_of? Array
+ raise JSS::InvalidDataError, 'JSS::Criteriable::Criteria instance required' unless @criteria.is_a? JSS::Criteriable::Criteria
+ raise JSS::InvalidDataError, 'display_fields must be an Array.' unless @display_fields.is_a? Array
orig_timeout = JSS::API.cnx.options[:timeout]
JSS::API.timeout = 1800
super()
requery_search_results if get_results
JSS::API.timeout = orig_timeout
@id # remember to return the id
-
end
- ###
- ### Save any changes
- ###
- ### If get_results is true, they'll be available in {#search_results}. This might be slow.
- ###
- ### @param get_results[Boolean] should the results of the search be queried immediately?
- ###
- ### @return [Integer] the id of the updated search
- ###
+ # Save any changes
+ #
+ # If get_results is true, they'll be available in {#search_results}. This might be slow.
+ #
+ # @param get_results[Boolean] should the results of the search be queried immediately?
+ #
+ # @return [Integer] the id of the updated search
+ #
def update(get_results = false)
orig_timeout = JSS::API.cnx.options[:timeout]
JSS::API.timeout = 1800
super()
requery_search_results if get_results
JSS::API.timeout = orig_timeout
- @id # remember to return the id
+ @id # remember to return the id
end
-
- ###
- ### Requery the API for the search results.
- ###
- ### This can be very slow, so temporarily reset the API timeout to 30 minutes
- ###
- ### @return [Array<Hash>] the new search results
- ###
+ # Requery the API for the search results.
+ #
+ # This can be very slow, so temporarily reset the API timeout to 30 minutes
+ #
+ # @return [Array<Hash>] the new search results
+ #
def requery_search_results
orig_open_timeout = JSS::API.cnx.options[:open_timeout]
orig_timeout = JSS::API.cnx.options[:timeout]
JSS::API.timeout = 1800
JSS::API.open_timeout = 1800
begin
- requery = self.class.new(:id => @id)
+ requery = self.class.new(id: @id)
@search_results = requery.search_results
@result_display_keys = requery.result_display_keys
ensure
JSS::API.timeout = orig_timeout
JSS::API.open_timeout = orig_open_timeout
end
end
- ###
- ### @return [Array<String>] the fields to be returned with the search results
- ###
- ### 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
- ### spaces and dashes converted to underscores, and they are
- ### symbolized.
- ###
- ###
- def display_fields
- @display_fields
- end
+ # @return [Array<String>] the fields to be returned with the search results
+ #
+ # 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
+ # spaces and dashes converted to underscores, and they are
+ # symbolized.
+ #
+ #
+ attr_reader :display_fields
- ###
- ### Set the list of fields to be retrieved with the
- ### search results.
- ###
- ### @param new_val[Array<String>] the new field names
- ###
- def display_fields= (new_val)
- raise JSS::InvalidDataError, "display_fields must be an Array." unless new_val.kind_of? Array
+ # Set the list of fields to be retrieved with the
+ # search results.
+ #
+ # @param new_val[Array<String>] the new field names
+ #
+ def display_fields=(new_val)
+ raise JSS::InvalidDataError, 'display_fields must be an Array.' unless new_val.is_a? Array
return if new_val.sort == @display_fields.sort
@display_fields = new_val
@need_to_update = true
end
-
-
- ###
- ### @return [Integer] the number of items found by the search
- ###
+ # @return [Integer] the number of items found by the search
+ #
def count
@search_results.count
end
- ###
- ### Export the display fields of the search results to a file.
- ###
- ### @param output_file[String,Pathname] The file in which to store the exported results
- ###
- ### @param format[Symbol] one of :csv, :tab, or :xml, defaults to :csv
- ###
- ### @param overwrite[Boolean] should the output_file be overwrite if it exists? Defaults to false
- ###
- ### @return [Pathname] the path to the output file
- ###
- ### @note This method only exports the display fields defined in this advanced search for
- ### 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)
- ###
+ # Export the display fields of the search results to a file.
+ #
+ # @param output_file[String,Pathname] The file in which to store the exported results
+ #
+ # @param format[Symbol] one of :csv, :tab, or :xml, defaults to :csv
+ #
+ # @param overwrite[Boolean] should the output_file be overwrite if it exists? Defaults to false
+ #
+ # @return [Pathname] the path to the output file
+ #
+ # @note This method only exports the display fields defined in this advanced search for
+ # 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)
+ #
def export(output_file, format = :csv, overwrite = false)
-
raise JSS::InvalidDataError, "Export format must be one of: :#{EXPORT_FORMATS.join ', :'}" unless EXPORT_FORMATS.include? format
out = Pathname.new output_file
unless overwrite
raise JSS::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"
+ when :csv
+ require 'csv'
+ CSV.open(out.to_s, 'wb') do |csv|
+ csv << @result_display_keys
@search_results.each do |row|
- tabbed << @result_display_keys.map {|key| row[key]}.join("\t") + "\n"
+ csv << @result_display_keys.map { |key| row[key] }
end # each do row
- out.jss_save tabbed.chomp
+ end # CSV.open
- 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.gsub(' ',"_")).text = row[field].empty? ? nil : row[field]
- end # ech do field
- end #each do row
- out.jss_save doc.to_s.gsub('><', ">\n<")
+ 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
- return out
+ out
end
-
+ # Private Instance Methods
#####################################
- ### Private Instance Methods
- #####################################
private
- ###
- ### Clean up the inconsistent "Display Field" keys in the search results.
- ###
- ### Sometimes spaces have been converted to underscores, sometimes not, sometimes both.
- ### Same for dashes.
- ### E.g :"Last Check-in"/:Last_Check_in/:"Last_Check-in", :Computer_Name, and :"Display Name"/:Display_Name
- ###
- ### This ensures there's always the fully underscored version.
- ###
- ### Update an internally used array of the display field names, symbolized, with
- ### spaces and dashes converted to underscores. We use these
- ### to overcome inconsistencies in how the names come from the API
- ###
- ### @return [void]
- ###
- def standardize_display_field_keys
- spdash=
- us =
- @display_field_std_keys = @display_fields.map{|f| f.gsub(/ |-/,"_").to_sym }
- end
+ # Clean up the inconsistent "Display Field" keys in the search results.
+ #
+ # Sometimes spaces have been converted to underscores, sometimes not, sometimes both.
+ # Same for dashes.
+ # E.g :"Last Check-in"/:Last_Check_in/:"Last_Check-in", :Computer_Name, and :"Display Name"/:Display_Name
+ #
+ # This ensures there's always the fully underscored version.
+ #
+ # Update an internally used array of the display field names, symbolized, with
+ # spaces and dashes converted to underscores. We use these
+ # to overcome inconsistencies in how the names come from the API
+ #
+ # @return [void]
+ #
+ # def standardize_display_field_keys
+ # spdash =
+ # us =
+ # @display_field_std_keys = @display_fields.map { |f| f.gsub(/ |-/, '_').to_sym }
+ # end
def rest_xml
doc = REXML::Document.new APIConnection::XML_HEADER
acs = doc.add_element self.class::RSRC_OBJECT_KEY.to_s
acs.add_element('name').text = @name
@@ -373,18 +339,17 @@
acs.add_element('sort_3').text = @sort_3 if @sort_3
acs << @criteria.rest_xml
df = acs.add_element('display_fields')
- @display_fields.each{|f| df.add_element('display_field').add_element('name').text = f }
+ @display_fields.each { |f| df.add_element('display_field').add_element('name').text = f }
- return doc.to_s
+ doc.to_s
end # rest xml
end # class AdvancedSearch
end # module JSS
-require "jss/api_object/advanced_search/advanced_computer_search"
-require "jss/api_object/advanced_search/advanced_mobile_device_search"
-require "jss/api_object/advanced_search/advanced_user_search"
-
+require 'jss/api_object/advanced_search/advanced_computer_search'
+require 'jss/api_object/advanced_search/advanced_mobile_device_search'
+require 'jss/api_object/advanced_search/advanced_user_search'