lib/jss/api_object/mobile_device.rb in ruby-jss-0.10.2a5 vs lib/jss/api_object/mobile_device.rb in ruby-jss-0.10.2

- old
+ new

@@ -37,52 +37,57 @@ # # This class represents a Mobile Device stored in the JSS. # # --- - # === Adding devices to the JSS + # ===Adding devices to the JSS # # This class cannot be used to add new mobile devices to the JSS. That can only be done # via the enrollment process. See JSS::MobileDeviceInvitation for sending # an enrollment invite to a device. # # --- - # === Editing values + # ===Editing values # # Only a few values can be changed via the API, using these methods, q.v: # - #asset_tag= String # - #extension_attribute= Hash of :name or :id, and :value # - #location= Hash of values in @location, not all are required # - #purchasing= Hash of values in @purchasing, not all are required # # After modfying any values, #save must be called to save changes to the JSS. # # --- - # === MDM Commands + # ===MDM Commands # - # See the {JSS::MDM} mixin module for Class and Instance methods for - # sending MDM commands to mobiledevices. + # The following methods can be used to send an APNS command to the device represented by an + # instance of JSS::MobileDevice, equivalent to clicking one of the buttons on + # the Management Commands section of the Management tab of the Mobile Device details page in the JSS UI. # - # To send MDM commands without fetching mobiledevice instances, use the class - # methods, which can take multiple identifiers at once. + # The methods supported are: + # - blank_push (aliases blank, noop, send_blank_push) + # - update_inventory (alias recon) + # - device_lock (aliases lock, lock_device) + # - erase_device (aliases wipe) + # - clear_passcode + # - unmanage_device (alias unmanage) # - # NOTE: If the {#name=} method is used to change the name of a supervized device, - # the DeviceName MDM command will be sent to the device when - # the changes are sent to the server via {#save} or {#update} + # Each returns true if the command as sent. # + # @see JSS::APIObject + # + # class MobileDevice < JSS::APIObject # Mix-Ins ##################################### include JSS::Updatable include JSS::Locatable include JSS::Purchasable include JSS::Uploadable include JSS::Extendable - include JSS::Sitable - include JSS::MDM extend JSS::Matchable # Class Constants ##################################### @@ -95,13 +100,10 @@ # The hash key used for the JSON object output. # It's also used in various error messages RSRC_OBJECT_KEY = :mobile_device - # Where is the Site data in the API JSON? - SITE_SUBSET = :general - # these keys, as well as :id and :name, are present in valid API JSON data for this class VALID_DATA_KEYS = %i[device_name capacity tethered].freeze # these keys, as well as :id and :name, can be used to look up objects of this class in the JSS OTHER_LOOKUP_KEYS = { @@ -116,14 +118,71 @@ SEARCH_CLASS = JSS::AdvancedMobileDeviceSearch # This is the class for relevant Extension Attributes EXT_ATTRIB_CLASS = JSS::MobileDeviceExtensionAttribute - # What kind of devices are we for MDM purposes? - MDM_COMMAND_TARGET = :mobiledevices + # the rsrc for mobile dev commands + MDM_RSRC = 'mobiledevicecommands/command'.freeze + # The MDM commands sendable via the api + # and alternative versions + # + MDM_COMMANDS = { + blank_push: 'BlankPush', + send_blank_push: 'BlankPush', + blank: 'BlankPush', + noop: 'BlankPush', + settings: 'Settings', + + update_inventory: 'UpdateInventory', + recon: 'UpdateInventory', + + device_lock: 'DeviceLock', + lock: 'DeviceLock', + lock_device: 'DeviceLock', + + erase_device: 'EraseDevice', + erase: 'EraseDevice', + wipe: 'EraseDevice', + + clear_passcode: 'ClearPasscode', + + clear_restrictions_password: 'ClearRestrictionsPassword', + + enable_data_roaming: 'SettingsEnableDataRoaming', + disable_data_roaming: 'SettingsDisableDataRoaming', + + enable_voice_roaming: 'SettingsEnableVoiceRoaming', + disable_voice_roaming: 'SettingsDisableVoiceRoaming', + + enable_app_analytics: 'SettingsEnableAppAnalytics', + disable_app_analytics: 'SettingsDisableAppAnalytics', + + enable_diagnostic_submission: 'SettingsEnableDiagnosticSubmission', + disable_diagnostic_submission: 'SettingsDisableDiagnosticSubmission', + + # wallpaper: 'Wallpaper', + + device_name: 'DeviceName', + + shutdown_device: 'ShutDownDevice', + shutdown: 'ShutDownDevice', + + restart_device: 'RestartDevice', + restart: 'RestartDevice', + + # passcode_lock_grace_period: 'PasscodeLockGracePeriod', + + unmanage_device: 'UnmanageDevice', + unmanage: 'UnmanageDevice' + + }.freeze + + # These MDM commands need extra data. + MDM_COMMANDS_REQUIRING_DATA = %w[DeviceLock DeviceName Wallpaper].freeze + # The History resource HISTORY_RSRC = 'mobiledevicehistory'.freeze # Available history subsets HISTORY_SUBSETS = %i[management_commands user_location audits applications ebooks].freeze @@ -137,80 +196,118 @@ # Class Methods ##################################### # @return [Array<String>] all mobiledevice serial_numbers def self.all_serial_numbers(refresh = false, api: JSS.api) - all(refresh, api: api).map { |i| i[:serial_number] } + all(refresh, api: API).map { |i| i[:serial_number] } end # @return [Array<String>] all mobiledevice phone numbers def self.all_phone_numbers(refresh = false, api: JSS.api) - all(refresh, api: api).map { |i| i[:phone_number] }.reject(&:empty?) + all(refresh, api: API).map { |i| i[:phone_number] }.reject(&:empty?) end # @return [Array<String>] all mobiledevice wifi mac addrs def self.all_wifi_mac_addresses(refresh = false, api: JSS.api) - all(refresh, api: api).map { |i| i[:wifi_mac_address] } + all(refresh, api: API).map { |i| i[:wifi_mac_address] } end # @return [Array<String>] all mobiledevice wifi mac addrs def self.all_mac_addresses(refresh = false, api: JSS.api) - all_wifi_mac_addresses(refresh, api: api) + all_wifi_mac_addresses(refresh, api: API) end # @return [Array<String>] all mobiledevice udids def self.all_udids(refresh = false, api: JSS.api) - all(refresh, api: api).map { |i| i[:udid] } + all(refresh, api: API).map { |i| i[:udid] } end # @return [Array<Hash>] the list of all managed mobile devices def self.all_managed(refresh = false, api: JSS.api) - all(refresh, api: api).select { |d| d[:managed] } + all(refresh, api: API).select { |d| d[:managed] } end # @return [Array<Hash>] the list of all unmanaged mobile devices def self.all_unmanaged(refresh = false, api: JSS.api) - all(refresh, api: api).reject { |d| d[:managed] } + all(refresh, api: API).reject { |d| d[:managed] } end - # @return [Array<Hash>] the list of all supervised mobile devices - def self.all_supervised(refresh = false, api: JSS.api) - all(refresh, api: api).select { |d| d[:supervised] } - end - - # @return [Array<Hash>] the list of all unsupervised mobile devices - def self.all_unsupervised(refresh = false, api: JSS.api) - all(refresh, api: api).reject { |d| d[:supervised] } - end - # @return [Array<Hash>] the list of all iPhones def self.all_iphones(refresh = false, api: JSS.api) - all(refresh, api: api).select { |d| d[:model].start_with? 'iPhone' } + all(refresh, api: API).select { |d| d[:model].start_with? 'iPhone' } end # @return [Array<Hash>] the list of all iPads def self.all_ipads(refresh = false, api: JSS.api) - all(refresh, api: api).select { |d| d[:model].start_with? 'iPad' } + all(refresh, api: API).select { |d| d[:model].start_with? 'iPad' } end # @return [Array<Hash>] the list of all iPads def self.all_apple_tvs(refresh = false, api: JSS.api) - all(refresh, api: api).select { |d| d[:model_identifier].start_with? 'AppleTV' } + all(refresh, api: API).select { |d| d[:model_identifier].start_with? 'AppleTV' } end + # Send an MDM command to one or more mobile devices by id or name + # + # + # @param targets[String,Integer,Array<String,Integer>] + # the name or id of the mobile devices to receive the command, or + # an array of such names or ids, or a comma-separated string + # of them. + # @param command[Symbol] the command to send, one of the keys + # of MDM_COMMANDS + # + # @param data[String] Some commands require extra data. + # + # @param api[JSS::APIConnection] the APi to query. Defaults to the + # currently active API, see {JSS::APIConnection} + # + # @return [String] The uuid of the MDM command sent, if applicable + # (blank pushes do not generate uuids) + # + def self.send_mdm_command(targets, command, data = nil, api: JSS.api) + raise JSS::NoSuchItemError, "Unknown command '#{command}'" unless MDM_COMMANDS.keys.include? command + + command = MDM_COMMANDS[command] + cmd_rsrc = "#{MDM_RSRC}/#{command}" + + if MDM_COMMANDS_REQUIRING_DATA.include? command + raise "MDM command '#{command}' requires additional data." unless data + cmd_rsrc << "/#{data}" + end + + targets = JSS.to_s_and_a(targets.to_s)[:arrayform] unless targets.is_a? Array + + # make sure its an array of ids + targets.map! do |md| + if all_ids(api: api).include? md.to_i + md.to_i + elsif all_names(api: api).include? md + map_all_ids_to(:name, api: api.invert[md]) + else + raise JSS::NoSuchItemError, "No mobile device found matching '#{md}'" + end # if + end # map! + + cmd_rsrc << "/id/#{targets.join ','}" + + result = api.post_rsrc cmd_rsrc, nil + result =~ %r{<uuid>(.*)</uuid>} + Regexp.last_match(1) + end + def self.management_history(identifier, subset = nil, api: JSS.api) id = nil if identifier.is_a? Integer id = identifier else - key = - case identifier - when *all_names(api: api) then :name - when *all_serial_numbers(api: api) then :serial_number - when *all_mac_addresses(api: api) then :mac_address - when *all_udids(api: api) then :udid - end + key = case identifier + when *all_names(api: api) then :name + when *all_serial_numbers(api: api) then :serial_number + when *all_mac_addresses(api: api) then :mac_address + when *all_udids(api: api) then :udid + end id = map_all_ids_to(key, api: api).invert[identifier] end # if identifier.is_a? Integer raise JSS::NoSuchItemError, "No MobileDevice found matching #{identifier}" unless id && all_ids(api: api).include?(id) @@ -395,13 +492,15 @@ # - :data_protection=>true, # - :block_level_encryption_capable=>true, # - :file_level_encryption_capable=>true attr_reader :security + ##################################### # Instance Methods ##################################### + # # @see APIObject#initialize # def initialize(args = {}) super args @@ -447,22 +546,194 @@ @provisioning_profiles = @init_data[:provisioning_profiles] @security = @init_data[:security] @applications = @init_data[:applications] end # initialize - def name=(new_name) - super - @needs_mdm_name_change = true if managed? && supervised? + # Send a blank_push MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def blank_push + self.class.send_mdm_command @id, :blank_push, api: @api + end # + + # Send an update_inventory MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def update_inventory + self.class.send_mdm_command @id, :update_inventory, api: @api end - def update - super - return unless @needs_mdm_name_change - self.class.send_mdm_command @id, :device_name, opts: { device_name: @name }, api: @api - @needs_mdm_name_change = false + # Send a device_lock MDM command + # + # @param message[String] The message to display on the lock screen. + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def device_lock(message) + self.class.send_mdm_command @id, :device_lock, message, api: @api end + # Send an erase_device MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def erase_device + self.class.send_mdm_command @id, :erase_device, api: @api + end + + # Send a clear_passcode MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def clear_passcode + self.class.send_mdm_command @id, :clear_passcode, api: @api + end + + # Send a unmanage_device MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def unmanage_device + @managed = false if self.class.send_mdm_command(@id, :unmanage_device, api: @api) + end + + # Send a ClearRestrictionsPassword MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def clear_restrictions_password + self.class.send_mdm_command @id, :clear_restrictions_password, api: @api + end + + # Send a SettingsEnableDataRoaming MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def enable_data_roaming + self.class.send_mdm_command @id, :enable_data_roaming, api: @api + end + + # Send a disable_data_roaming MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def disable_data_roaming + self.class.send_mdm_command @id, :disable_data_roaming, api: @api + end + + # Send a enable_voice_roaming MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def enable_voice_roaming + self.class.send_mdm_command @id, :enable_voice_roaming, api: @api + end + + # Send a disable_voice_roaming MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def disable_voice_roaming + self.class.send_mdm_command @id, :disable_voice_roaming, api: @api + end + + # Send a enable_app_analytics MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def enable_app_analytics + self.class.send_mdm_command @id, :enable_app_analytics, api: @api + end + + # Send a disable_app_analytics MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def disable_app_analytics + self.class.send_mdm_command @id, :disable_app_analytics, api: @api + end + + # Send a enable_diagnostic_submission MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def enable_diagnostic_submission + self.class.send_mdm_command @id, :enable_diagnostic_submission, api: @api + end + + # Send a disable_diagnostic_submission MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def disable_diagnostic_submission + self.class.send_mdm_command @id, :disable_diagnostic_submission, api: @api + end + + # Send a device_name MDM command + # + # @param new_name[String] The name for the device + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def device_name(new_name) + self.class.send_mdm_command @id, :device_name, new_name, api: @api + end + + # Send a shutdown device MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def shutdown + self.class.send_mdm_command @id, :shutdown, api: @api + end + + # Send a restart device MDM command + # + # @see MobileDevice.send_mdm_command + # + # @return [String] The command uuid + # + def restart + self.class.send_mdm_command @id, :restart, api: @api + end + # The full management History data for this Mobile Device # # @return [Hash] Keys are: # general: Hash of identifiers # user_location: see user_location_history @@ -651,28 +922,36 @@ # Aliases alias battery_percent battery_level alias managed? managed - alias supervised? supervised alias sn serial_number alias serialnumber serial_number + alias noop blank_push + alias send_blank_push blank_push + alias recon update_inventory + alias lock device_lock + alias lock_device device_lock + alias erase erase_device + alias wipe erase_device + alias unmanage unmanage_device + alias make_unmanaged unmanage_device - - # private methods ############################## private def rest_xml doc = REXML::Document.new APIConnection::XML_HEADER md = doc.add_element self.class::RSRC_OBJECT_KEY.to_s - md << ext_attr_xml + + md << ext_attr_xml if @changed_eas && !@changed_eas.empty? + md << location_xml if has_location? md << purchasing_xml if has_purchasing? - add_site_to_xml doc + doc.to_s end end # class Mobile Device