ruby-jss 0.10.1 → 0.10.2a4

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.

@@ -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
  #
@@ -174,6 +167,8 @@ module JSS
174
167
  include JSS::Purchasable
175
168
  include JSS::Uploadable
176
169
  include JSS::Extendable
170
+ include JSS::Sitable
171
+ include JSS::MDM
177
172
 
178
173
  extend JSS::Matchable
179
174
 
@@ -193,6 +188,9 @@ module JSS
193
188
  # It's also used in various error messages
194
189
  RSRC_OBJECT_KEY = :computer
195
190
 
191
+ # Where is the Site data in the API JSON?
192
+ SITE_SUBSET = :general
193
+
196
194
  # these keys, as well as :id and :name, are present in valid API JSON data for this class
197
195
  # DEPRECATED, with be removed in a future release.
198
196
  VALID_DATA_KEYS = %i[sus distribution_point alt_mac_address].freeze
@@ -218,32 +216,8 @@ module JSS
218
216
  # file uploads can send attachments to the JSS using :computers as the sub-resource.
219
217
  UPLOAD_TYPES = { attachment: :computers }.freeze
220
218
 
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
219
+ # Tell the MDM module what kind of MDM commands we use.
220
+ MDM_COMMAND_TARGET = :computers
247
221
 
248
222
  # The API resource for app usage
249
223
  APPLICATION_USAGE_RSRC = 'computerapplicationusage'.freeze
@@ -299,8 +273,6 @@ module JSS
299
273
  # converted to strings) and the second-level hash key of the
300
274
  # returned subset data.
301
275
  #
302
- # The values are the key within each history item that contains the
303
- # 'epoch' timestamp, for conver
304
276
  HISTORY_SUBSETS = %i[
305
277
  computer_usage_logs
306
278
  audits
@@ -313,17 +285,29 @@ module JSS
313
285
  mac_app_store_applications
314
286
  ].freeze
315
287
 
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
288
+ # Most History Subsets contain Arrays of Hashes.
289
+ #
290
+ # However, these contain a Hash of Arrays of Hashes:
291
+ #
292
+ # :commands is a hash with these keys:
293
+ # :completed - An array of hashes about completed MDM commands
294
+ # :pending - An array of hashes about pending MDM commands
295
+ # :failed - An array of hashes about failed MDM commands
296
+ #
297
+ # :mac_app_store_applications is a hash with these keys:
298
+ # :installed - An array of hashes about installed apps
299
+ # :pending - An array of hashes about apps pending installation
300
+ # :failed - An array of hashes about apps that failed to install.
301
+ #
302
+ # The .history class and instance methods for JSS::Computer re-organize
303
+ # those data structures to be consistent with the other subsets of history
304
+ # data by turning them into an Array of Hashes, where each hash has a
305
+ # :status key containing :completed/:installed, :pending, or :failed
306
+ #
307
+ # See {JSS::Computer.full_history}, {JSS::Computer.history_subset} and
308
+ # {JSS::Computer.standardize_history_subset} class methods for details.
309
+ #
310
+ HISTORY_INCONSISTENT_SUBSETS = %i[commands mac_app_store_applications].freeze
327
311
 
328
312
  POLICY_STATUS_COMPLETED = 'Completed'.freeze
329
313
 
@@ -331,12 +315,23 @@ module JSS
331
315
 
332
316
  POLICY_STATUS_PENDING = 'Pending'.freeze
333
317
 
318
+ COMMAND_STATUS_COMPLETED = :completed
319
+
320
+ COMMAND_STATUS_PENDING = :pending
321
+
322
+ COMMAND_STATUS_FAILED = :failed
323
+
324
+ APP_STORE_APP_STATUS_INSTALLED = :installed
325
+
326
+ APP_STORE_APP_STATUS_PENDING = :pending
327
+
328
+ APP_STORE_APP_STATUS_FAILED = :failed
329
+
334
330
  # the object type for this object in
335
331
  # the object history table.
336
332
  # See {APIObject#add_object_history_entry}
337
333
  OBJECT_HISTORY_OBJECT_TYPE = 1
338
334
 
339
-
340
335
  # Class Methods
341
336
  #####################################
342
337
 
@@ -463,56 +458,191 @@ module JSS
463
458
  all(refresh, api: api).select { |d| d[:model] =~ /^macpro/i }
464
459
  end
465
460
 
466
- # Send an MDM command to one or more managed computers by id or name
461
+ # Retrieve Application Usage data for a computer by id, without
462
+ # instantiation.
467
463
  #
464
+ # @param ident [Integer,String] An identifier (id, name, serialnumber,
465
+ # macadress or udid) of the computer for which to retrieve Application Usage
468
466
  #
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
467
+ # @param start_date [Time,Date,DateTime,String] The earliest date to retrieve
475
468
  #
476
- # @param passcode[String] some commands require a 6-character passcode
469
+ # @param end_date [String,Date,DateTime,Time] Defaults to start_date
477
470
  #
478
471
  # @param api[JSS::APIConnection] an API connection to use for the query.
479
472
  # Defaults to the corrently active API. See {JSS::APIConnection}
480
473
  #
481
- # @return [String] The uuid of the MDM command sent, if applicable
482
- # (blank pushes do not generate uuids)
474
+ # @return [Hash{Date=>Array<Hash>}] A Hash with keys (Date instances) for
475
+ # each day in the range.
483
476
  #
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
477
+ # Each hash value contains an Array of apps used
478
+ # on that day.
479
+ #
480
+ # Each item in the array is a hash of data about the app.
481
+ # Those hash keys are:
482
+ # :name => String, the name of the app
483
+ # :version => String ,the version of the app
484
+ # :foreground => Integer, the minutes it was in the foreground
485
+ # :open => Integer, the minutes it was running.
486
+ #
487
+ def self.application_usage(ident, start_date, end_date = nil, api: JSS.api)
488
+ id = valid_id ident, api: api
489
+ raise "No computer matches identifier: #{ident}" unless id
490
+ end_date ||= start_date
491
+ start_date = Time.parse start_date if start_date.is_a? String
492
+ end_date = Time.parse end_date if end_date.is_a? String
493
+ unless ([start_date.class, end_date.class] - APPLICATION_USAGE_DATE_CLASSES).empty?
494
+ raise JSS::InvalidDataError, 'Invalid Start or End Date'
495
+ end
496
+ start_date = start_date.strftime APPLICATION_USAGE_DATE_FMT
497
+ end_date = end_date.strftime APPLICATION_USAGE_DATE_FMT
498
+ data = api.get_rsrc(APPLICATION_USAGE_RSRC + "/id/#{id}/#{start_date}_#{end_date}")
499
+ parsed_data = {}
500
+ data[APPLICATION_USAGE_KEY].each do |day_hash|
501
+ date = Date.parse day_hash[:date]
502
+ parsed_data[date] = day_hash[:apps]
503
+ end
504
+ parsed_data
505
+ end # app usage
486
506
 
487
- command = COMPUTER_MDM_COMMANDS[command]
488
- cmd_rsrc = "#{COMPUTER_MDM_RSRC}/#{command}"
507
+ # The 'computer management' data for a given computer by id,
508
+ # looked up on the fly.
509
+ #
510
+ # Without specifying a subset:, the entire dataset is returned as a hash of
511
+ # arrays, one per subset
512
+ #
513
+ # If a subset is given then only that array is returned, and it contains
514
+ # hashes with data about each item (usually :name and :id)
515
+ #
516
+ # If the only: param is provided with a subset, it is used as a hash-key to
517
+ # map the array to just those values, so subset: :smart_groups, only: :name
518
+ # will return an array of names of smartgroups that contain the computer.
519
+ #
520
+ # @param ident [Integer,String] An identifier (id, name, serialnumber,
521
+ # macadress or udid) of the computer for which to retrieve Application Usage
522
+ #
523
+ # @param subset[Symbol] Fetch only a subset of data, as an array.
524
+ # must be one of the symbols in MGMT_DATA_SUBSETS
525
+ #
526
+ # @param only[Symbol] When fetching a subset, only return one value
527
+ # per item in the array. meaningless without a subset.
528
+ #
529
+ # @param api[JSS::APIConnection] an API connection to use for the query.
530
+ # Defaults to the corrently active API. See {JSS::APIConnection}
531
+ #
532
+ # @return [Hash] Without a subset:, a hash of all subsets, each of which is
533
+ # an Array
534
+ #
535
+ # @return [Array] With a subset:, an array of items in that subset, possibly
536
+ # limited to just certain values with only:
537
+ #
538
+ def self.management_data(ident, subset: nil, only: nil, api: JSS.api)
539
+ id = valid_id ident, api: api
540
+ raise "No computer matches identifier: #{ident}" unless id
541
+ if subset
542
+ management_data_subset id, subset: subset, only: only, api: api
543
+ else
544
+ full_management_data id, api: api
545
+ end
546
+ end
547
+
548
+ # The full set of management data for a given computer.
549
+ # This private method is called by self.management_data, q.v.
550
+ #
551
+ def self.full_management_data(id, api: JSS.api)
552
+ mgmt_rsrc = MGMT_DATA_RSRC + "/id/#{id}"
553
+ api.get_rsrc(mgmt_rsrc)[MGMT_DATA_KEY]
554
+ end
555
+ private_class_method :full_management_data
556
+
557
+ # A subset of management data for a given computer.
558
+ # This private method is called by self.management_data, q.v.
559
+ #
560
+ def self.management_data_subset(id, subset: nil, only: nil, api: JSS.api)
561
+ raise "Subset must be one of :#{MGMT_DATA_SUBSETS.join ', :'}" unless MGMT_DATA_SUBSETS.include? subset
562
+ subset_rsrc = MGMT_DATA_RSRC + "/id/#{id}/subset/#{subset}"
563
+ subset_data = api.get_rsrc(subset_rsrc)[MGMT_DATA_KEY]
564
+ return subset_data unless only
565
+ subset_data.map { |d| d[only] }
566
+ end
567
+ private_class_method :management_data_subset
489
568
 
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}"
569
+ # Return this computer's management history.
570
+ # WARNING: Its huge, better to use a subset.
571
+ #
572
+ # NOTE: ruby-jss standardizes the inconsistent data-stucture of the subsets,
573
+ # so they may not exactly match the raw API output.
574
+ # See {JSS::Computer::HISTORY_INCONSISTENT_SUBSETS} for details
575
+ #
576
+ # @param ident [Integer,String] An identifier (id, name, serialnumber,
577
+ # macadress or udid) of the computer for which to retrieve Application Usage
578
+ #
579
+ # @param subset[Symbol] the subset to return, rather than full history.
580
+ #
581
+ # @param api[JSS::APIConnection] an API connection to use for the query.
582
+ # Defaults to the corrently active API. See {JSS::APIConnection}
583
+ #
584
+ # @return [Hash] The full history.
585
+ #
586
+ # @return [Array] The requested subset.
587
+ #
588
+ def self.history(ident, subset: nil, api: JSS.api)
589
+ id = valid_id ident, api: api
590
+ raise JSS::NoSuchItemError, "No Computer matches identifier: #{ident}" unless id
591
+
592
+ if subset
593
+ history_subset id, subset: subset, api: api
594
+ else
595
+ full_history id, api: api
495
596
  end
597
+ end
496
598
 
497
- targets = JSS.to_s_and_a(targets.to_s)[:arrayform] unless targets.is_a? Array
599
+ # The full management history for a given computer.
600
+ # This private method is called by self.history, q.v.
601
+ #
602
+ def self.full_history(id, api: JSS.api)
603
+ hist = api.get_rsrc(HISTORY_RSRC + "/id/#{id}")[HISTORY_KEY]
498
604
 
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!
605
+ # rework the :commands and :mac_app_store_applications into a consistent data structure
606
+ HISTORY_INCONSISTENT_SUBSETS.each do |subset|
607
+ hist[subset] = standardize_history_subset hist[subset]
608
+ end # :commands, :mac_app_store_applications].each do |subsect|
609
+ hist
610
+ end
611
+ private_class_method :full_history
509
612
 
510
- cmd_rsrc << "/id/#{targets.join ','}"
613
+ # A subset of the management history for a given computer.
614
+ # This private method is called by self.history, q.v.
615
+ #
616
+ def self.history_subset(id, subset: nil, api: JSS.api)
617
+ raise "Subset must be one of :#{HISTORY_SUBSETS.join ', :'}" unless HISTORY_SUBSETS.include? subset
618
+ subset_rsrc = HISTORY_RSRC + "/id/#{id}/subset/#{subset}"
619
+ subset_data = api.get_rsrc(subset_rsrc)[HISTORY_KEY][subset]
620
+ return standardize_history_subset(subset_data) if HISTORY_INCONSISTENT_SUBSETS.include? subset
621
+ subset_data
622
+ end
623
+ private_class_method :history_subset
511
624
 
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
625
+ # rework the inconsistent data structure of :commands and
626
+ # :mac_app_store_applications (Hash of Arrays of Hashes)
627
+ # to the same structure as the other subsets (Array of Hashes)
628
+ #
629
+ # @param raw_data [Hash] The raw, inconsistent data structure from the API
630
+ #
631
+ # @return [Array] the same data restructured to match the rest of the
632
+ # computer history subsets: An Array of Hashes, one per event, each with
633
+ # a :status key.
634
+ #
635
+ def self.standardize_history_subset(raw_data)
636
+ consistency_array = []
637
+ raw_data.each do |status, events|
638
+ events.each do |evt|
639
+ evt[:status] = status
640
+ consistency_array << evt
641
+ end # cmd_events.each
642
+ end # raw_hist[:commands].each
643
+ consistency_array
644
+ end
645
+ private_class_method :standardize_history_subset
516
646
 
517
647
 
518
648
  # Attributes
@@ -840,239 +970,173 @@ module JSS
840
970
 
841
971
  # Get application usage data for this computer
842
972
  # 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.
973
+ # See {JSS::Computer.application_usage} for details
857
974
  #
858
975
  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
976
+ JSS::Computer.application_usage @id, start_date, end_date, api: @api
874
977
  end # app usage
875
978
 
876
- # The 'computer management' data for this computer, looked up on the fly.
877
- #
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)
882
- #
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
979
+ # The 'computer management' data for this computer
892
980
  #
893
- # @param only[Symbol] When fetching a subset, only return one value
894
- # per item in the array. meaningless without a subset.
981
+ # NOTE: the data isn't cached locally, and the API is queried every time
895
982
  #
896
- # @param refresh[Boolean] should the data be re-cached from the API?
983
+ # See {JSS::Computer.management_data} for details
897
984
  #
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
985
+ def management_data(subset: nil, only: nil)
986
+ raise JSS::NoSuchItemError, 'Computer not yet saved in the JSS' unless @in_jss
987
+ JSS::Computer.management_data @id, subset: subset, only: only, api: @api
910
988
  end
911
989
 
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] }
929
- end
930
- private :management_data_subset
931
-
932
990
  # A shortcut for 'management_data subset: :smart_groups'
933
991
  #
934
- def smart_groups(only: nil, refresh: false)
935
- management_data subset: :smart_groups, only: only, refresh: refresh
992
+ def smart_groups(only: nil)
993
+ management_data subset: :smart_groups, only: only
936
994
  end
937
995
 
938
996
  # A shortcut for 'management_data subset: :static_groups'
939
997
  #
940
- def static_groups(only: nil, refresh: false)
941
- management_data subset: :static_groups, only: only, refresh: refresh
998
+ def static_groups(only: nil)
999
+ management_data subset: :static_groups, only: only
942
1000
  end
943
1001
 
944
1002
  # A shortcut for 'management_data subset: :policies'
945
1003
  #
946
- def policies(only: nil, refresh: false)
947
- management_data subset: :policies, only: only, refresh: refresh
1004
+ def policies(only: nil)
1005
+ management_data subset: :policies, only: only
948
1006
  end
949
1007
 
950
1008
  # A shortcut for 'management_data subset: :os_x_configuration_profiles'
951
1009
  #
952
- def configuration_profiles(only: nil, refresh: false)
953
- management_data subset: :os_x_configuration_profiles, only: only, refresh: refresh
1010
+ def configuration_profiles(only: nil)
1011
+ management_data subset: :os_x_configuration_profiles, only: only
954
1012
  end
955
1013
 
956
1014
  # A shortcut for 'management_data subset: :ebooks'
957
1015
  #
958
- def ebooks(only: nil, refresh: false)
1016
+ def ebooks(only: nil)
959
1017
  management_data subset: :ebooks, only: only, refresh: refresh
960
1018
  end
961
1019
 
962
1020
  # A shortcut for 'management_data subset: :mac_app_store_apps'
963
1021
  #
964
- def app_store_apps(only: nil, refresh: false)
965
- management_data subset: :mac_app_store_apps, only: only, refresh: refresh
1022
+ def app_store_apps(only: nil)
1023
+ management_data subset: :mac_app_store_apps, only: only
966
1024
  end
967
1025
 
968
1026
  # A shortcut for 'management_data subset: :restricted_software'
969
1027
  #
970
- def restricted_software(only: nil, refresh: false)
971
- management_data subset: :restricted_software, only: only, refresh: refresh
1028
+ def restricted_software(only: nil)
1029
+ management_data subset: :restricted_software, only: only
972
1030
  end
973
1031
 
974
1032
  # A shortcut for 'management_data subset: :patch_reporting_software_titles'
975
1033
  #
976
- def patch_titles(only: nil, refresh: false)
977
- management_data subset: :patch_reporting_software_titles, only: only, refresh: refresh
1034
+ def patch_titles(only: nil)
1035
+ management_data subset: :patch_reporting_software_titles, only: only
978
1036
  end
979
1037
 
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.
1038
+ # Return this computer's management history.
1039
+ # WARNING: Its huge, better to use a subset or one of the shortcut methods.
986
1040
  #
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?
1041
+ # NOTE: This is not the same as a computer's Object History
990
1042
  #
991
- # @return [Hash] The full history
1043
+ # NOTE: The data isn't cached locally, the API is queried every time
992
1044
  #
993
- # @return [Array] The history subset requested
1045
+ # For details, see {JSS::Computer.history}
994
1046
  #
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]
1047
+ def history(subset: nil)
1048
+ JSS::Computer.history @id, subset: subset, api: @api
1020
1049
  end
1021
- private :history_subset
1022
1050
 
1023
1051
  # Shortcut for history(:computer_usage_logs)
1024
- def usage_logs(refresh = false)
1025
- history(subset: :computer_usage_logs, refresh: refresh)
1052
+ def usage_logs
1053
+ history subset: :computer_usage_logs
1026
1054
  end
1027
1055
 
1028
1056
  # Shortcut for history(:audits)
1029
- def audits(refresh = false)
1030
- history(subset: :audits, refresh: refresh)
1057
+ def audits
1058
+ history subset: :audits
1031
1059
  end
1032
1060
 
1033
1061
  # Shortcut for history(:policy_logs)
1034
- def policy_logs(refresh = false)
1035
- history(subset: :policy_logs, refresh: refresh)
1062
+ def policy_logs
1063
+ history subset: :policy_logs
1036
1064
  end
1037
1065
 
1038
1066
  # 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 }
1067
+ def completed_policies
1068
+ policy_logs.select { |pl| pl[:status] == POLICY_STATUS_COMPLETED }
1041
1069
  end
1042
1070
 
1043
1071
  # 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 }
1072
+ def failed_policies
1073
+ policy_logs.select { |pl| pl[:status] == POLICY_STATUS_FAILED }
1046
1074
  end
1047
1075
 
1048
1076
  # Shortcut for history(:casper_remote_logs)
1049
- def casper_remote_logs(refresh = false)
1050
- history(subset: :casper_remote_logs, refresh: refresh)
1077
+ def casper_remote_logs
1078
+ history subset: :casper_remote_logs
1051
1079
  end
1052
1080
 
1053
1081
  # Shortcut for history(:screen_sharing_logs)
1054
- def screen_sharing_logs(refresh = false)
1055
- history(subset: :screen_sharing_logs, refresh: refresh)
1082
+ def screen_sharing_logs
1083
+ history subset: :screen_sharing_logs
1056
1084
  end
1057
1085
 
1058
1086
  # Shortcut for history(:casper_imaging_logs)
1059
- def casper_imaging_logs(refresh = false)
1060
- history(subset: :casper_imaging_logs, refresh: refresh)
1087
+ def casper_imaging_logs
1088
+ history subset: :casper_imaging_logs
1061
1089
  end
1062
1090
 
1063
1091
  # Shortcut for history(:commands)
1064
- def commands(refresh = false)
1065
- history(subset: :commands, refresh: refresh)
1092
+ def commands
1093
+ history subset: :commands
1094
+ end
1095
+
1096
+ # Shortcut for history(:commands) but just the completed commands
1097
+ #
1098
+ def completed_commands
1099
+ commands.select { |cmd| cmd[:status] == COMMAND_STATUS_COMPLETED }
1100
+ end
1101
+
1102
+ # Shortcut for history(:commands) but just the pending commands
1103
+ #
1104
+ def pending_commands
1105
+ commands.select { |cmd| cmd[:status] == COMMAND_STATUS_PENDING }
1106
+ end
1107
+
1108
+ # Shortcut for history(:commands) but just the failed commands
1109
+ #
1110
+ def failed_commands
1111
+ commands.select { |cmd| cmd[:status] == COMMAND_STATUS_FAILED }
1066
1112
  end
1067
1113
 
1068
1114
  # Shortcut for history(:user_location)
1069
- def user_location_history(refresh = false)
1070
- history(subset: :user_location, refresh: refresh)
1115
+ def user_location_history
1116
+ history subset: :user_location
1071
1117
  end
1072
1118
 
1073
1119
  # Shortcut for history(:mac_app_store_applications)
1074
- def app_store_app_history(refresh = false)
1075
- history(subset: :mac_app_store_applications, refresh: refresh)
1120
+ def app_store_app_history
1121
+ history subset: :mac_app_store_applications
1122
+ end
1123
+
1124
+ # Shortcut for history(:mac_app_store_applications) but just the installed apps
1125
+ #
1126
+ def installed_app_store_apps
1127
+ app_store_app_history.select { |app| app[:status] == APP_STORE_APP_STATUS_INSTALLED }
1128
+ end
1129
+
1130
+ # Shortcut for history(:mac_app_store_applications) but just the pending apps
1131
+ #
1132
+ def pending_app_store_apps
1133
+ app_store_app_history.select { |app| app[:status] == APP_STORE_APP_STATUS_PENDING }
1134
+ end
1135
+
1136
+ # Shortcut for history(:mac_app_store_applications) but just the failed apps
1137
+ #
1138
+ def failed_app_store_apps
1139
+ app_store_app_history.select { |app| app[:status] == APP_STORE_APP_STATUS_FAILED }
1076
1140
  end
1077
1141
 
1078
1142
  # Set or unset management acct and password for this computer
@@ -1177,10 +1241,9 @@ module JSS
1177
1241
  # @return [void]
1178
1242
  #
1179
1243
  def update
1180
- id = super
1181
- remove_mdm_profile if mdm_capable && managed? && @unmange_at_update
1244
+ remove_mdm_profile if mdm_capable && @unmange_at_update
1182
1245
  @unmange_at_update = false
1183
- id
1246
+ super
1184
1247
  end
1185
1248
 
1186
1249
  # Delete this computer from the JSS
@@ -1228,47 +1291,6 @@ module JSS
1228
1291
  @software = nil
1229
1292
  end # delete
1230
1293
 
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
1294
 
1273
1295
  # aliases
1274
1296
  alias alt_macaddress alt_mac_address
@@ -1320,6 +1342,8 @@ module JSS
1320
1342
 
1321
1343
  computer << purchasing_xml if has_purchasing?
1322
1344
 
1345
+ add_site_to_xml(doc)
1346
+
1323
1347
  doc.to_s
1324
1348
  end # rest_xml
1325
1349