ruby-jss 0.10.2 → 0.11.0a5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-jss might be problematic. Click here for more details.

Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +49 -2
  3. data/README.md +14 -7
  4. data/lib/jss/api_connection.rb +48 -24
  5. data/lib/jss/api_object/advanced_search.rb +5 -1
  6. data/lib/jss/api_object/computer.rb +204 -402
  7. data/lib/jss/api_object/computer_invitation.rb +5 -3
  8. data/lib/jss/api_object/ebook.rb +5 -0
  9. data/lib/jss/api_object/extendable.rb +13 -0
  10. data/lib/jss/api_object/group/computer_group.rb +4 -0
  11. data/lib/jss/api_object/group/mobile_device_group.rb +4 -1
  12. data/lib/jss/api_object/group.rb +6 -1
  13. data/lib/jss/api_object/mac_application.rb +5 -0
  14. data/lib/jss/api_object/management_history/audit_event.rb +45 -0
  15. data/lib/jss/api_object/management_history/casper_imaging_log.rb +37 -0
  16. data/lib/jss/api_object/management_history/casper_remote_log.rb +37 -0
  17. data/lib/jss/api_object/management_history/computer_usage_log.rb +43 -0
  18. data/lib/jss/api_object/management_history/ebook.rb +70 -0
  19. data/lib/jss/api_object/management_history/mac_app_store_app.rb +69 -0
  20. data/lib/jss/api_object/management_history/mdm_command.rb +96 -0
  21. data/lib/jss/api_object/management_history/mobile_device_app.rb +99 -0
  22. data/lib/jss/api_object/management_history/policy_log.rb +60 -0
  23. data/lib/jss/api_object/management_history/screen_sharing_log.rb +41 -0
  24. data/lib/jss/api_object/management_history/user_location_change.rb +66 -0
  25. data/lib/jss/api_object/management_history.rb +865 -0
  26. data/lib/jss/api_object/mdm.rb +1298 -0
  27. data/lib/jss/api_object/mobile_device.rb +241 -644
  28. data/lib/jss/api_object/mobile_device_application.rb +6 -0
  29. data/lib/jss/api_object/mobile_device_configuration_profile.rb +36 -0
  30. data/lib/jss/api_object/osx_configuration_profile.rb +115 -151
  31. data/lib/jss/api_object/patch.rb +38 -0
  32. data/lib/jss/api_object/patch_policy.rb +38 -0
  33. data/lib/jss/api_object/peripheral.rb +5 -7
  34. data/lib/jss/api_object/policy.rb +5 -0
  35. data/lib/jss/api_object/restricted_software.rb +5 -0
  36. data/lib/jss/api_object/scopable/scope.rb +367 -411
  37. data/lib/jss/api_object/self_servable.rb +15 -4
  38. data/lib/jss/api_object/sitable.rb +197 -0
  39. data/lib/jss/api_object/site.rb +45 -76
  40. data/lib/jss/api_object/user.rb +7 -3
  41. data/lib/jss/api_object.rb +75 -4
  42. data/lib/jss/utility.rb +21 -0
  43. data/lib/jss/version.rb +1 -1
  44. data/lib/jss.rb +6 -0
  45. metadata +42 -6
@@ -63,31 +63,24 @@ module JSS
63
63
  #
64
64
  # === MDM Commands
65
65
  #
66
- # The following methods can be used to send an APNS command to the
67
- # computer represented by an instance of JSS::Computer, equivalent to
68
- # clicking one of the buttons on the Management Commands section of the
69
- # Management tab of the Computer details page in the JSS UI.
66
+ # See the {JSS::MDM} mixin module for Class and Instance methods for
67
+ # sending MDM commands to computers.
70
68
  #
71
- # - {#blank_push} (aliases blank, noop, send_blank_push)
72
- # - {#device_lock} (aliases lock, lock_device)
73
- # - {#erase_device} (aliases wipe)
74
- # - {#remove_mdm_profile}
69
+ # To send MDM commands without fetching Computer instances, use the class
70
+ # methods, which can take multiple computer identifiers at once.
75
71
  #
76
- # To send an MDM command without making a Computer instance, use the class
77
- # {JSS::Computer.send_mdm_command} which can take multiple computer
78
- # identifiers at once.
79
- #
80
- # NOTE: the poorly named 'UnmanageDevice' command via the API is implemented
81
- # as the {#remove_mdm_profile} method (which is its name in the webUI).
82
- # Calling that method will NOT unmanage the machine from the JSS's point
72
+ # NOTE: the poorly named 'UnmanageDevice' mdm command is implemented
73
+ # as {#remove_mdm_profile} (which is its name in the webUI) as well as
74
+ # {#unmanage_device}.
75
+ # Calling that method will NOT fully unmanage a computer from the JSS's point
83
76
  # of view, it will just remove the mdm management profile from the machine
84
77
  # and all configuration profiles that were installed via the JSS. Those
85
78
  # profiles may be re-installed automatically later if the computer is still in
86
79
  # scope for them
87
80
  #
88
- # The {#make_unmanaged} method also removes the mdm profile, but actually
89
- # does make the machine unmanged by the JSS, setting the management acct to
90
- # nil, and requring re-enrollment.
81
+ # To properly unmanage a computer, use the {#make_unmanaged} Instance method
82
+ # which removes the mdm profile, but also makes the machine unmanged by the
83
+ # JSS, setting the management acct to nil, and requring re-enrollment.
91
84
  #
92
85
  # === Computer History
93
86
  #
@@ -168,12 +161,15 @@ module JSS
168
161
 
169
162
  # MixIns
170
163
  #####################################
171
-
164
+ include JSS::Creatable
172
165
  include JSS::Updatable
173
166
  include JSS::Locatable
174
167
  include JSS::Purchasable
175
168
  include JSS::Uploadable
176
169
  include JSS::Extendable
170
+ include JSS::Sitable
171
+ include JSS::MDM
172
+ include JSS::ManagementHistory
177
173
 
178
174
  extend JSS::Matchable
179
175
 
@@ -193,6 +189,9 @@ module JSS
193
189
  # It's also used in various error messages
194
190
  RSRC_OBJECT_KEY = :computer
195
191
 
192
+ # Where is the Site data in the API JSON?
193
+ SITE_SUBSET = :general
194
+
196
195
  # these keys, as well as :id and :name, are present in valid API JSON data for this class
197
196
  # DEPRECATED, with be removed in a future release.
198
197
  VALID_DATA_KEYS = %i[sus distribution_point alt_mac_address].freeze
@@ -218,32 +217,8 @@ module JSS
218
217
  # file uploads can send attachments to the JSS using :computers as the sub-resource.
219
218
  UPLOAD_TYPES = { attachment: :computers }.freeze
220
219
 
221
- # The base REST resource for sending computer MDM commands
222
- COMPUTER_MDM_RSRC = 'computercommands/command'.freeze
223
-
224
- # A mapping of Symbols available to the send_mdm_command class method, to
225
- # the String commands actuallly sent via the API.
226
- COMPUTER_MDM_COMMANDS = {
227
- blank_push: 'BlankPush',
228
- blankpush: 'BlankPush',
229
- send_blank_push: 'BlankPush',
230
- blank: 'BlankPush',
231
- noop: 'BlankPush',
232
- device_lock: 'DeviceLock',
233
- devicelock: 'DeviceLock',
234
- lock: 'DeviceLock',
235
- lock_device: 'DeviceLock',
236
- erase_device: 'EraseDevice',
237
- erasedevice: 'EraseDevice',
238
- erase: 'EraseDevice',
239
- wipe: 'EraseDevice',
240
- unmanage_device: 'UnmanageDevice',
241
- unmanagedevice: 'UnmanageDevice',
242
- unmanage: 'UnmanageDevice'
243
- }.freeze
244
-
245
- # these MDM commands require a passcode
246
- COMPUTER_MDM_COMMANDS_NEEDING_PASSCODE = %w[DeviceLock EraseDevice].freeze
220
+ # Tell the MDM module what kind of MDM commands we use.
221
+ MDM_COMMAND_TARGET = :computers
247
222
 
248
223
  # The API resource for app usage
249
224
  APPLICATION_USAGE_RSRC = 'computerapplicationusage'.freeze
@@ -289,54 +264,11 @@ module JSS
289
264
  # The top-level hash key for the inventory collection settings
290
265
  INV_COLLECTION_KEY = :computer_inventory_collection
291
266
 
292
- # The API Resource for the computer history data
293
- HISTORY_RSRC = 'computerhistory'.freeze
294
-
295
- # The top-level hash key for the history data
296
- HISTORY_KEY = :computer_history
297
-
298
- # The keys are both the subset names in the resrouce URLS (when
299
- # converted to strings) and the second-level hash key of the
300
- # returned subset data.
301
- #
302
- # The values are the key within each history item that contains the
303
- # 'epoch' timestamp, for conver
304
- HISTORY_SUBSETS = %i[
305
- computer_usage_logs
306
- audits
307
- policy_logs
308
- casper_remote_logs
309
- screen_sharing_logs
310
- casper_imaging_logs
311
- commands
312
- user_location
313
- mac_app_store_applications
314
- ].freeze
315
-
316
- # HISTORY_SUBSETS = %i(
317
- # computer_usage_logs date_time_epoch
318
- # audits
319
- # policy_logs date_completed_epoch
320
- # casper_remote_logs date_time_epoch
321
- # screen_sharing_logs date_time_epoch
322
- # casper_imaging_logs
323
- # commands completed_epoch
324
- # user_location
325
- # mac_app_store_applications
326
- # ).freeze
327
-
328
- POLICY_STATUS_COMPLETED = 'Completed'.freeze
329
-
330
- POLICY_STATUS_FAILED = 'Failed'.freeze
331
-
332
- POLICY_STATUS_PENDING = 'Pending'.freeze
333
-
334
267
  # the object type for this object in
335
268
  # the object history table.
336
269
  # See {APIObject#add_object_history_entry}
337
270
  OBJECT_HISTORY_OBJECT_TYPE = 1
338
271
 
339
-
340
272
  # Class Methods
341
273
  #####################################
342
274
 
@@ -463,64 +395,120 @@ module JSS
463
395
  all(refresh, api: api).select { |d| d[:model] =~ /^macpro/i }
464
396
  end
465
397
 
466
- # Send an MDM command to one or more managed computers by id or name
398
+ # Retrieve Application Usage data for a computer by id, without
399
+ # instantiation.
467
400
  #
401
+ # @param ident [Integer,String] An identifier (id, name, serialnumber,
402
+ # macadress or udid) of the computer for which to retrieve Application Usage
468
403
  #
469
- # @param targets[String,Integer,Array<String,Integer>]
470
- # the name or id of the computer to receive the command, or
471
- # an array of such names or ids, or a comma-separated string
472
- # of them.
473
- # @param command[Symbol] the command to send, one of the keys
474
- # of COMPUTER_MDM_COMMANDS
404
+ # @param start_date [Time,Date,DateTime,String] The earliest date to retrieve
475
405
  #
476
- # @param passcode[String] some commands require a 6-character passcode
406
+ # @param end_date [String,Date,DateTime,Time] Defaults to start_date
477
407
  #
478
408
  # @param api[JSS::APIConnection] an API connection to use for the query.
479
409
  # Defaults to the corrently active API. See {JSS::APIConnection}
480
410
  #
481
- # @return [String] The uuid of the MDM command sent, if applicable
482
- # (blank pushes do not generate uuids)
411
+ # @return [Hash{Date=>Array<Hash>}] A Hash with keys (Date instances) for
412
+ # each day in the range.
483
413
  #
484
- def self.send_mdm_command(targets, command, passcode = nil, api: JSS.api)
485
- raise JSS::NoSuchItemError, "Unknown command '#{command}'" unless COMPUTER_MDM_COMMANDS.keys.include? command
486
-
487
- command = COMPUTER_MDM_COMMANDS[command]
488
- cmd_rsrc = "#{COMPUTER_MDM_RSRC}/#{command}"
489
-
490
- if COMPUTER_MDM_COMMANDS_NEEDING_PASSCODE.include? command
491
- unless passcode && passcode.is_a?(String) && passcode.length == 6
492
- raise JSS::MissingDataError, "Command '#{command}' requires a 6-character passcode"
493
- end
494
- cmd_rsrc << "/passcode/#{passcode}"
414
+ # Each hash value contains an Array of apps used
415
+ # on that day.
416
+ #
417
+ # Each item in the array is a hash of data about the app.
418
+ # Those hash keys are:
419
+ # :name => String, the name of the app
420
+ # :version => String ,the version of the app
421
+ # :foreground => Integer, the minutes it was in the foreground
422
+ # :open => Integer, the minutes it was running.
423
+ #
424
+ def self.application_usage(ident, start_date, end_date = nil, api: JSS.api)
425
+ id = valid_id ident, api: api
426
+ raise "No computer matches identifier: #{ident}" unless id
427
+ end_date ||= start_date
428
+ start_date = Time.parse start_date if start_date.is_a? String
429
+ end_date = Time.parse end_date if end_date.is_a? String
430
+ unless ([start_date.class, end_date.class] - APPLICATION_USAGE_DATE_CLASSES).empty?
431
+ raise JSS::InvalidDataError, 'Invalid Start or End Date'
495
432
  end
433
+ start_date = start_date.strftime APPLICATION_USAGE_DATE_FMT
434
+ end_date = end_date.strftime APPLICATION_USAGE_DATE_FMT
435
+ data = api.get_rsrc(APPLICATION_USAGE_RSRC + "/id/#{id}/#{start_date}_#{end_date}")
436
+ parsed_data = {}
437
+ data[APPLICATION_USAGE_KEY].each do |day_hash|
438
+ date = Date.parse day_hash[:date]
439
+ parsed_data[date] = day_hash[:apps]
440
+ end
441
+ parsed_data
442
+ end # app usage
496
443
 
497
- targets = JSS.to_s_and_a(targets.to_s)[:arrayform] unless targets.is_a? Array
498
-
499
- # make sure its an array of ids
500
- targets.map! do |comp|
501
- if all_ids(api: api).include? comp.to_i
502
- comp.to_i
503
- elsif all_names(api: api).include? comp
504
- map_all_ids_to(:name, api: api).invert[comp]
505
- else
506
- raise JSS::NoSuchItemError, "No computer found matching '#{comp}'"
507
- end # if
508
- end # map!
509
-
510
- cmd_rsrc << "/id/#{targets.join ','}"
444
+ # The 'computer management' data for a given computer by id,
445
+ # looked up on the fly.
446
+ #
447
+ # Without specifying a subset:, the entire dataset is returned as a hash of
448
+ # arrays, one per subset
449
+ #
450
+ # If a subset is given then only that array is returned, and it contains
451
+ # hashes with data about each item (usually :name and :id)
452
+ #
453
+ # If the only: param is provided with a subset, it is used as a hash-key to
454
+ # map the array to just those values, so subset: :smart_groups, only: :name
455
+ # will return an array of names of smartgroups that contain the computer.
456
+ #
457
+ # @param ident [Integer,String] An identifier (id, name, serialnumber,
458
+ # macadress or udid) of the computer for which to retrieve Application Usage
459
+ #
460
+ # @param subset[Symbol] Fetch only a subset of data, as an array.
461
+ # must be one of the symbols in MGMT_DATA_SUBSETS
462
+ #
463
+ # @param only[Symbol] When fetching a subset, only return one value
464
+ # per item in the array. meaningless without a subset.
465
+ #
466
+ # @param api[JSS::APIConnection] an API connection to use for the query.
467
+ # Defaults to the corrently active API. See {JSS::APIConnection}
468
+ #
469
+ # @return [Hash] Without a subset:, a hash of all subsets, each of which is
470
+ # an Array
471
+ #
472
+ # @return [Array] With a subset:, an array of items in that subset, possibly
473
+ # limited to just certain values with only:
474
+ #
475
+ def self.management_data(ident, subset: nil, only: nil, api: JSS.api)
476
+ id = valid_id ident, api: api
477
+ raise "No computer matches identifier: #{ident}" unless id
478
+ if subset
479
+ management_data_subset id, subset: subset, only: only, api: api
480
+ else
481
+ full_management_data id, api: api
482
+ end
483
+ end
511
484
 
512
- result = api.post_rsrc cmd_rsrc, nil
513
- result =~ %r{<command_uuid>(.*)</command_uuid>}
514
- Regexp.last_match(1)
515
- end # send mdm command
485
+ # The full set of management data for a given computer.
486
+ # This private method is called by self.management_data, q.v.
487
+ #
488
+ def self.full_management_data(id, api: JSS.api)
489
+ mgmt_rsrc = MGMT_DATA_RSRC + "/id/#{id}"
490
+ api.get_rsrc(mgmt_rsrc)[MGMT_DATA_KEY]
491
+ end
492
+ private_class_method :full_management_data
516
493
 
494
+ # A subset of management data for a given computer.
495
+ # This private method is called by self.management_data, q.v.
496
+ #
497
+ def self.management_data_subset(id, subset: nil, only: nil, api: JSS.api)
498
+ raise "Subset must be one of :#{MGMT_DATA_SUBSETS.join ', :'}" unless MGMT_DATA_SUBSETS.include? subset
499
+ subset_rsrc = MGMT_DATA_RSRC + "/id/#{id}/subset/#{subset}"
500
+ subset_data = api.get_rsrc(subset_rsrc)[MGMT_DATA_KEY]
501
+ return subset_data unless only
502
+ subset_data.map { |d| d[only] }
503
+ end
504
+ private_class_method :management_data_subset
517
505
 
518
506
  # Attributes
519
507
  #####################################
520
508
 
521
- # The values returned in the General, Location, and Purchasing subsets are stored as direct attributes
522
- # Location and Purchasing are defined in the Locatable and Purchasable mixin modules.
523
- # Here's General, in alphabetical order
509
+ # identifiers
510
+ ################
511
+
524
512
 
525
513
  # @return [String] the secondary mac address
526
514
  attr_reader :alt_mac_address
@@ -540,6 +528,9 @@ module JSS
540
528
  # @return [IPAddr] the last known IP address
541
529
  attr_reader :ip_address
542
530
 
531
+ # @return [Boolean]
532
+ attr_reader :itunes_store_account_is_active
533
+
543
534
  # @return [String] the version of the jamf binary
544
535
  attr_reader :jamf_version
545
536
 
@@ -561,6 +552,13 @@ module JSS
561
552
  # @return [Boolean] doesit support MDM?
562
553
  attr_reader :mdm_capable
563
554
 
555
+ # @return [Array] user accts that support MDM?
556
+ # NOTE: This suffers from the JSON-Hash-treated-like_XML-Array-loses-data
557
+ # bug and only shows the last listed user, cuz it comes from the API
558
+ # as a hash, not an array.
559
+ #
560
+ attr_reader :mdm_capable_users
561
+
564
562
  # @return [String] the name of the netboot server for this machine
565
563
  attr_reader :netboot_server
566
564
 
@@ -740,42 +738,57 @@ module JSS
740
738
 
741
739
  # @param (see APIObject#initialize)
742
740
  #
743
- # As well as :id and :name, computers can be queried using :udid, :serialnumber, and :mac_address
741
+ # # When creating new records with .make,
742
+ # these can be provided in the arg, or after instantiation via
743
+ # setter methods:
744
+ # serial_number:, udid:, asset_tag:, mac_address:
745
+ # alt_mac_address:, barcode_1:, barcode_2:
746
+ #
744
747
  #
745
748
  def initialize(args = {})
746
749
  super args
747
-
748
- # now we have raw @init_data with something in it, so fill out the instance vars
749
- @alt_mac_address = @init_data[:general][:alt_mac_address]
750
- @asset_tag = @init_data[:general][:asset_tag]
751
- @barcode_1 = @init_data[:general][:barcode_1]
752
- @barcode_2 = @init_data[:general][:barcode_2]
753
- @distribution_point = @init_data[:general][:distribution_point]
754
- @initial_entry_date = JSS.epoch_to_time @init_data[:general][:initial_entry_date_epoch]
755
- @last_enrolled = JSS.epoch_to_time @init_data[:general][:last_enrolled_date_epoch]
756
- @ip_address = @init_data[:general][:ip_address]
757
- @jamf_version = @init_data[:general][:jamf_version]
758
- @last_contact_time = JSS.epoch_to_time @init_data[:general][:last_contact_time_epoch]
759
- @mac_address = @init_data[:general][:mac_address]
760
- @managed = @init_data[:general][:remote_management][:managed]
761
- @management_username = @init_data[:general][:remote_management][:management_username]
762
- @mdm_capable = @init_data[:general][:mdm_capable]
763
- @netboot_server = @init_data[:general][:netboot_server]
764
- @platform = @init_data[:general][:platform]
765
- @report_date = JSS.epoch_to_time @init_data[:general][:report_date_epoch]
766
- @serial_number = @init_data[:general][:serial_number]
767
- @site = JSS::APIObject.get_name(@init_data[:general][:site])
768
- @sus = @init_data[:general][:sus]
769
- @udid = @init_data[:general][:udid]
770
-
771
- @configuration_profiles = @init_data[:configuration_profiles]
772
- @extension_attributes = @init_data[:extension_attributes]
773
- @groups_accounts = @init_data[:groups_accounts]
774
- @hardware = @init_data[:hardware]
775
- @peripherals = @init_data[:peripherals]
776
- @software = @init_data[:software]
777
-
778
- @management_password = nil
750
+ if @in_jss
751
+ @alt_mac_address = @init_data[:general][:alt_mac_address]
752
+ @asset_tag = @init_data[:general][:asset_tag]
753
+ @barcode_1 = @init_data[:general][:barcode_1]
754
+ @barcode_2 = @init_data[:general][:barcode_2]
755
+ @distribution_point = @init_data[:general][:distribution_point]
756
+ @initial_entry_date = JSS.epoch_to_time @init_data[:general][:initial_entry_date_epoch]
757
+ @last_enrolled = JSS.epoch_to_time @init_data[:general][:last_enrolled_date_epoch]
758
+ @ip_address = @init_data[:general][:ip_address]
759
+ @itunes_store_account_is_active = @init_data[:general][:itunes_store_account_is_active]
760
+ @jamf_version = @init_data[:general][:jamf_version]
761
+ @last_contact_time = JSS.epoch_to_time @init_data[:general][:last_contact_time_epoch]
762
+ @mac_address = @init_data[:general][:mac_address]
763
+ @managed = @init_data[:general][:remote_management][:managed]
764
+ @management_username = @init_data[:general][:remote_management][:management_username]
765
+ @mdm_capable = @init_data[:general][:mdm_capable]
766
+ @mdm_capable_users = @init_data[:general][:mdm_capable_users].values
767
+ @netboot_server = @init_data[:general][:netboot_server]
768
+ @platform = @init_data[:general][:platform]
769
+ @report_date = JSS.epoch_to_time @init_data[:general][:report_date_epoch]
770
+ @serial_number = @init_data[:general][:serial_number]
771
+ @site = JSS::APIObject.get_name(@init_data[:general][:site])
772
+ @sus = @init_data[:general][:sus]
773
+ @udid = @init_data[:general][:udid]
774
+
775
+ @configuration_profiles = @init_data[:configuration_profiles]
776
+ @certificates = @init_data[:certificates]
777
+ @groups_accounts = @init_data[:groups_accounts]
778
+ @hardware = @init_data[:hardware]
779
+ @peripherals = @init_data[:peripherals]
780
+ @software = @init_data[:software]
781
+
782
+ @management_password = nil
783
+ else
784
+ @udid = args[:udid]
785
+ @serial_number = args[:serial_number]
786
+ @asset_tag = args[:asset_tag]
787
+ @mac_address = args[:mac_address]
788
+ @alt_mac_address = args[:alt_mac_address]
789
+ @barcode_1 = args[:barcode_1]
790
+ @barcode_2 = args[:barcode_2]
791
+ end
779
792
  end # initialize
780
793
 
781
794
  # @return [Array] the JSS groups to which thismachine belongs (smart and static)
@@ -840,239 +853,69 @@ module JSS
840
853
 
841
854
  # Get application usage data for this computer
842
855
  # for a given date range.
843
- #
844
- # TODO: Make this a class method so we can retrieve it without
845
- # instantiating the Computer.
846
- #
847
- # @param start_date [String,Date,DateTime,Time]
848
- #
849
- # @param end_date [String,Date,DateTime,Time] Defaults to start_date
850
- #
851
- # @return [Hash{Date=>Array<Hash>}] For each day in the range, an Array
852
- # with one Hash per application used. The hash keys are:
853
- # :name => String, the name of the app
854
- # :version => String ,the version of the app
855
- # :foreground => Integer, the minutes it was in the foreground
856
- # :open => Integer, the minutes it was running.
856
+ # See {JSS::Computer.application_usage} for details
857
857
  #
858
858
  def application_usage(start_date, end_date = nil)
859
- end_date ||= start_date
860
- start_date = Time.parse start_date if start_date.is_a? String
861
- end_date = Time.parse end_date if end_date.is_a? String
862
- unless ([start_date.class, end_date.class] - APPLICATION_USAGE_DATE_CLASSES).empty?
863
- raise JSS::InvalidDataError, 'Invalid Start or End Date'
864
- end
865
- start_date = start_date.strftime APPLICATION_USAGE_DATE_FMT
866
- end_date = end_date.strftime APPLICATION_USAGE_DATE_FMT
867
- data = @api.get_rsrc(APPLICATION_USAGE_RSRC + "/id/#{@id}/#{start_date}_#{end_date}")
868
- parsed_data = {}
869
- data[APPLICATION_USAGE_KEY].each do |day_hash|
870
- date = Date.parse day_hash[:date]
871
- parsed_data[date] = day_hash[:apps]
872
- end
873
- parsed_data
859
+ JSS::Computer.application_usage @id, start_date, end_date, api: @api
874
860
  end # app usage
875
861
 
876
- # The 'computer management' data for this computer, looked up on the fly.
862
+ # The 'computer management' data for this computer
877
863
  #
878
- # Without specifying a subset:, the entire dataset is returned as a hash of
879
- # arrays, one per subset
880
- # If a subset is given then only that array is returned, and it contains
881
- # hashes with data about each item (usually :name and :id)
864
+ # NOTE: the data isn't cached locally, and the API is queried every time
882
865
  #
883
- # If the only: param is provided with a subset, it is used as a hash-key to
884
- # map the array to just those values, so subset: :smart_groups, only: :name
885
- # will return an array of names of smartgroups that contain this computer.
886
- #
887
- # TODO: Make this a class method so we can retrieve it without
888
- # instantiating the Computer.
889
- #
890
- # @param subset[Symbol] Fetch only a subset of data, as an array.
891
- # must be one of the symbols in MGMT_DATA_SUBSETS
866
+ # @see {JSS::Computer.management_data} for details
892
867
  #
893
- # @param only[Symbol] When fetching a subset, only return one value
894
- # per item in the array. meaningless without a subset.
895
- #
896
- # @param refresh[Boolean] should the data be re-cached from the API?
897
- #
898
- # @return [Hash] Without a subset:, a hash of all subsets, each of which is
899
- # an Array
900
- #
901
- # @return [Array] With a subset:, an array of items in that subset.
902
- #
903
- def management_data(subset: nil, only: nil, refresh: false)
904
- @management_data ||= {}
905
- if subset
906
- management_data_subset(subset: subset, only: only, refresh: refresh)
907
- else
908
- full_management_data refresh
909
- end
910
- end
911
-
912
- def full_management_data(refresh = false)
913
- @management_data[:full] = nil if refresh
914
- return @management_data[:full] if @management_data[:full]
915
- mgmt_rsrc = MGMT_DATA_RSRC + "/id/#{@id}"
916
- @management_data[:full] = @api.get_rsrc(mgmt_rsrc)[MGMT_DATA_KEY]
917
- @management_data[:full]
918
- end
919
- private :full_management_data
920
-
921
- def management_data_subset(subset: nil, only: nil, refresh: false)
922
- raise "Subset must be one of :#{MGMT_DATA_SUBSETS.join ', :'}" unless MGMT_DATA_SUBSETS.include? subset
923
- @management_data[subset] = nil if refresh
924
- return @management_data[subset] if @management_data[subset]
925
- subset_rsrc = MGMT_DATA_RSRC + "/id/#{@id}/subset/#{subset}"
926
- @management_data[subset] = @api.get_rsrc(subset_rsrc)[MGMT_DATA_KEY]
927
- return @management_data[subset] unless only
928
- @management_data[subset].map { |d| d[only] }
868
+ def management_data(subset: nil, only: nil)
869
+ raise JSS::NoSuchItemError, 'Computer not yet saved in the JSS' unless @in_jss
870
+ JSS::Computer.management_data @id, subset: subset, only: only, api: @api
929
871
  end
930
- private :management_data_subset
931
872
 
932
873
  # A shortcut for 'management_data subset: :smart_groups'
933
874
  #
934
- def smart_groups(only: nil, refresh: false)
935
- management_data subset: :smart_groups, only: only, refresh: refresh
875
+ def smart_groups(only: nil)
876
+ management_data subset: :smart_groups, only: only
936
877
  end
937
878
 
938
879
  # A shortcut for 'management_data subset: :static_groups'
939
880
  #
940
- def static_groups(only: nil, refresh: false)
941
- management_data subset: :static_groups, only: only, refresh: refresh
881
+ def static_groups(only: nil)
882
+ management_data subset: :static_groups, only: only
942
883
  end
943
884
 
944
885
  # A shortcut for 'management_data subset: :policies'
945
886
  #
946
- def policies(only: nil, refresh: false)
947
- management_data subset: :policies, only: only, refresh: refresh
887
+ def policies(only: nil)
888
+ management_data subset: :policies, only: only
948
889
  end
949
890
 
950
891
  # A shortcut for 'management_data subset: :os_x_configuration_profiles'
951
892
  #
952
- def configuration_profiles(only: nil, refresh: false)
953
- management_data subset: :os_x_configuration_profiles, only: only, refresh: refresh
893
+ def configuration_profiles(only: nil)
894
+ management_data subset: :os_x_configuration_profiles, only: only
954
895
  end
955
896
 
956
897
  # A shortcut for 'management_data subset: :ebooks'
957
898
  #
958
- def ebooks(only: nil, refresh: false)
899
+ def ebooks(only: nil)
959
900
  management_data subset: :ebooks, only: only, refresh: refresh
960
901
  end
961
902
 
962
903
  # A shortcut for 'management_data subset: :mac_app_store_apps'
963
904
  #
964
- def app_store_apps(only: nil, refresh: false)
965
- management_data subset: :mac_app_store_apps, only: only, refresh: refresh
905
+ def app_store_apps(only: nil)
906
+ management_data subset: :mac_app_store_apps, only: only
966
907
  end
967
908
 
968
909
  # A shortcut for 'management_data subset: :restricted_software'
969
910
  #
970
- def restricted_software(only: nil, refresh: false)
971
- management_data subset: :restricted_software, only: only, refresh: refresh
911
+ def restricted_software(only: nil)
912
+ management_data subset: :restricted_software, only: only
972
913
  end
973
914
 
974
915
  # A shortcut for 'management_data subset: :patch_reporting_software_titles'
975
916
  #
976
- def patch_titles(only: nil, refresh: false)
977
- management_data subset: :patch_reporting_software_titles, only: only, refresh: refresh
978
- end
979
-
980
- # Return this computer's history.
981
- # WARNING! Its huge, better to use a subset a
982
- # nd one of the shortcut methods.
983
- #
984
- # TODO: Make this a class method so we can retrieve it without
985
- # instantiating the Computer.
986
- #
987
- # @param subset[Symbol] the subset to return, rather than full history.
988
- #
989
- # @param refresh[Boolean] should we re-cache the data from the API?
990
- #
991
- # @return [Hash] The full history
992
- #
993
- # @return [Array] The history subset requested
994
- #
995
- def history(subset: nil, refresh: false)
996
- @history ||= {}
997
- if subset
998
- history_subset(subset: subset, refresh: refresh)
999
- else
1000
- full_history refresh
1001
- end
1002
- end
1003
-
1004
- def full_history(refresh = false)
1005
- @history[:full] = nil if refresh
1006
- return @history[:full] if @history[:full]
1007
- history_rsrc = HISTORY_RSRC + "/id/#{@id}"
1008
- @history[:full] = @api.get_rsrc(history_rsrc)[HISTORY_KEY]
1009
- @history[:full]
1010
- end
1011
- private :full_history
1012
-
1013
- def history_subset(subset: nil, refresh: false)
1014
- raise "Subset must be one of :#{HISTORY_SUBSETS.join ', :'}" unless HISTORY_SUBSETS.include? subset
1015
- @history[subset] = nil if refresh
1016
- return @history[subset] if @history[subset]
1017
- subset_rsrc = HISTORY_RSRC + "/id/#{@id}/subset/#{subset}"
1018
- @history[subset] = @api.get_rsrc(subset_rsrc)[HISTORY_KEY]
1019
- @history[subset]
1020
- end
1021
- private :history_subset
1022
-
1023
- # Shortcut for history(:computer_usage_logs)
1024
- def usage_logs(refresh = false)
1025
- history(subset: :computer_usage_logs, refresh: refresh)
1026
- end
1027
-
1028
- # Shortcut for history(:audits)
1029
- def audits(refresh = false)
1030
- history(subset: :audits, refresh: refresh)
1031
- end
1032
-
1033
- # Shortcut for history(:policy_logs)
1034
- def policy_logs(refresh = false)
1035
- history(subset: :policy_logs, refresh: refresh)
1036
- end
1037
-
1038
- # Shortcut for history(:policy_logs), but just the completed policies
1039
- def completed_policies(refresh = false)
1040
- policy_logs(refresh).select { |pl| pl[:status] == POLICY_STATUS_COMPLETED }
1041
- end
1042
-
1043
- # Shortcut for history(:policy_logs), but just the failes policies
1044
- def failed_policies(refresh = false)
1045
- policy_log(refresh).select { |pl| pl[:status] == POLICY_STATUS_FAILED }
1046
- end
1047
-
1048
- # Shortcut for history(:casper_remote_logs)
1049
- def casper_remote_logs(refresh = false)
1050
- history(subset: :casper_remote_logs, refresh: refresh)
1051
- end
1052
-
1053
- # Shortcut for history(:screen_sharing_logs)
1054
- def screen_sharing_logs(refresh = false)
1055
- history(subset: :screen_sharing_logs, refresh: refresh)
1056
- end
1057
-
1058
- # Shortcut for history(:casper_imaging_logs)
1059
- def casper_imaging_logs(refresh = false)
1060
- history(subset: :casper_imaging_logs, refresh: refresh)
1061
- end
1062
-
1063
- # Shortcut for history(:commands)
1064
- def commands(refresh = false)
1065
- history(subset: :commands, refresh: refresh)
1066
- end
1067
-
1068
- # Shortcut for history(:user_location)
1069
- def user_location_history(refresh = false)
1070
- history(subset: :user_location, refresh: refresh)
1071
- end
1072
-
1073
- # Shortcut for history(:mac_app_store_applications)
1074
- def app_store_app_history(refresh = false)
1075
- history(subset: :mac_app_store_applications, refresh: refresh)
917
+ def patch_titles(only: nil)
918
+ management_data subset: :patch_reporting_software_titles, only: only
1076
919
  end
1077
920
 
1078
921
  # Set or unset management acct and password for this computer
@@ -1177,10 +1020,9 @@ module JSS
1177
1020
  # @return [void]
1178
1021
  #
1179
1022
  def update
1180
- id = super
1181
- remove_mdm_profile if mdm_capable && managed? && @unmange_at_update
1023
+ remove_mdm_profile if mdm_capable && @unmange_at_update
1182
1024
  @unmange_at_update = false
1183
- id
1025
+ super
1184
1026
  end
1185
1027
 
1186
1028
  # Delete this computer from the JSS
@@ -1228,48 +1070,6 @@ module JSS
1228
1070
  @software = nil
1229
1071
  end # delete
1230
1072
 
1231
- # Send a blank_push MDM command
1232
- #
1233
- # See JSS::Computer.send_mdm_command
1234
- #
1235
- def blank_push
1236
- self.class.send_mdm_command @id, :blank_push, api: @api
1237
- end
1238
- alias noop blank_push
1239
- alias send_blank_push blank_push
1240
-
1241
- # Send a device_lock MDM command
1242
- #
1243
- # See JSS::Computer.send_mdm_command
1244
- #
1245
- def device_lock(passcode)
1246
- self.class.send_mdm_command @id, :device_lock, passcode, api: @api
1247
- end
1248
- alias lock device_lock
1249
- alias lock_device device_lock
1250
-
1251
- # Send an erase_device MDM command
1252
- #
1253
- # See JSS::Computer.send_mdm_command
1254
- #
1255
- def erase_device(passcode)
1256
- self.class.send_mdm_command @id, :erase_device, passcode, api: @api
1257
- end
1258
- alias erase erase_device
1259
- alias wipe erase_device
1260
-
1261
- # Remove MDM management profile without
1262
- # un-enrolling from the JSS or
1263
- # resetting the JSS management acct.
1264
- #
1265
- # To do those things as well, see {#make_unmanaged}
1266
- #
1267
- # See JSS::Computer.send_mdm_command
1268
- #
1269
- def remove_mdm_profile
1270
- self.class.send_mdm_command @id, :unmanage_device, api: @api
1271
- end
1272
-
1273
1073
  # aliases
1274
1074
  alias alt_macaddress alt_mac_address
1275
1075
  alias bar_code_1 barcode_1
@@ -1314,12 +1114,14 @@ module JSS
1314
1114
  rmgmt.add_element('management_username').text = @management_username
1315
1115
  rmgmt.add_element('management_password').text = @management_password if @management_password
1316
1116
 
1317
- computer << ext_attr_xml if @changed_eas && !@changed_eas.empty?
1117
+ computer << ext_attr_xml if unsaved_eas?
1318
1118
 
1319
1119
  computer << location_xml if has_location?
1320
1120
 
1321
1121
  computer << purchasing_xml if has_purchasing?
1322
1122
 
1123
+ add_site_to_xml(doc)
1124
+
1323
1125
  doc.to_s
1324
1126
  end # rest_xml
1325
1127