ruby-jss 0.6.5 → 0.6.6

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +57 -5
  3. data/lib/jss.rb +78 -94
  4. data/lib/jss/api_connection.rb +8 -0
  5. data/lib/jss/api_object.rb +126 -102
  6. data/lib/jss/api_object/creatable.rb +33 -15
  7. data/lib/jss/api_object/distribution_point.rb +4 -1
  8. data/lib/jss/api_object/extension_attribute.rb +1 -1
  9. data/lib/jss/api_object/package.rb +121 -187
  10. data/lib/jss/api_object/policy.rb +590 -251
  11. data/lib/jss/api_object/script.rb +92 -128
  12. data/lib/jss/api_object/self_servable.rb +93 -117
  13. data/lib/jss/api_object/updatable.rb +12 -27
  14. data/lib/jss/api_object/uploadable.rb +12 -15
  15. data/lib/jss/client.rb +178 -156
  16. data/lib/jss/db_connection.rb +34 -49
  17. data/lib/jss/ruby_extensions/string.rb +25 -21
  18. data/lib/jss/version.rb +1 -1
  19. data/lib/jss/webhooks.rb +52 -0
  20. data/lib/jss/webhooks/README.md +269 -0
  21. data/lib/jss/webhooks/configuration.rb +212 -0
  22. data/lib/jss/webhooks/data/sample_handlers/RestAPIOperation-executable +90 -0
  23. data/lib/jss/webhooks/data/sample_handlers/RestAPIOperation.rb +44 -0
  24. data/lib/jss/webhooks/data/sample_jsons/ComputerAdded.json +27 -0
  25. data/lib/jss/webhooks/data/sample_jsons/ComputerCheckIn.json +27 -0
  26. data/lib/jss/webhooks/data/sample_jsons/ComputerInventoryCompleted.json +27 -0
  27. data/lib/jss/webhooks/data/sample_jsons/ComputerPolicyFinished.json +27 -0
  28. data/lib/jss/webhooks/data/sample_jsons/ComputerPushCapabilityChanged.json +27 -0
  29. data/lib/jss/webhooks/data/sample_jsons/JSSShutdown.json +14 -0
  30. data/lib/jss/webhooks/data/sample_jsons/JSSStartup.json +14 -0
  31. data/lib/jss/webhooks/data/sample_jsons/MobileDeviceCheckIn.json +26 -0
  32. data/lib/jss/webhooks/data/sample_jsons/MobileDeviceCommandCompleted.json +26 -0
  33. data/lib/jss/webhooks/data/sample_jsons/MobileDeviceEnrolled.json +26 -0
  34. data/lib/jss/webhooks/data/sample_jsons/MobileDevicePushSent.json +26 -0
  35. data/lib/jss/webhooks/data/sample_jsons/MobileDeviceUnEnrolled.json +26 -0
  36. data/lib/jss/webhooks/data/sample_jsons/PatchSoftwareTitleUpdated.json +14 -0
  37. data/lib/jss/webhooks/data/sample_jsons/PushSent.json +11 -0
  38. data/lib/jss/webhooks/data/sample_jsons/RestAPIOperation.json +15 -0
  39. data/lib/jss/webhooks/data/sample_jsons/SCEPChallenge.json +10 -0
  40. data/lib/jss/webhooks/data/sample_jsons/SmartGroupComputerMembershipChange.json +13 -0
  41. data/lib/jss/webhooks/data/sample_jsons/SmartGroupMobileDeviceMembershipChange.json +13 -0
  42. data/lib/jss/webhooks/event.rb +138 -0
  43. data/lib/jss/webhooks/event/computer_added.rb +37 -0
  44. data/lib/jss/webhooks/event/computer_check_in.rb +37 -0
  45. data/lib/jss/webhooks/event/computer_inventory_completed.rb +37 -0
  46. data/lib/jss/webhooks/event/computer_policy_finished.rb +37 -0
  47. data/lib/jss/webhooks/event/computer_push_capability_changed.rb +37 -0
  48. data/lib/jss/webhooks/event/handlers.rb +191 -0
  49. data/lib/jss/webhooks/event/jss_shutdown.rb +37 -0
  50. data/lib/jss/webhooks/event/jss_startup.rb +37 -0
  51. data/lib/jss/webhooks/event/mobile_device_check_in.rb +37 -0
  52. data/lib/jss/webhooks/event/mobile_device_command_completed.rb +37 -0
  53. data/lib/jss/webhooks/event/mobile_device_enrolled.rb +37 -0
  54. data/lib/jss/webhooks/event/mobile_device_push_sent.rb +37 -0
  55. data/lib/jss/webhooks/event/mobile_device_unenrolled.rb +37 -0
  56. data/lib/jss/webhooks/event/patch_software_title_updated.rb +37 -0
  57. data/lib/jss/webhooks/event/push_sent.rb +37 -0
  58. data/lib/jss/webhooks/event/rest_api_operation.rb +37 -0
  59. data/lib/jss/webhooks/event/scep_challenge.rb +37 -0
  60. data/lib/jss/webhooks/event/smart_group_computer_membership_change.rb +37 -0
  61. data/lib/jss/webhooks/event/smart_group_mobile_device_membership_change.rb +37 -0
  62. data/lib/jss/webhooks/event/webhook.rb +39 -0
  63. data/lib/jss/webhooks/event_objects.rb +111 -0
  64. data/lib/jss/webhooks/event_objects/computer.rb +48 -0
  65. data/lib/jss/webhooks/event_objects/jss.rb +35 -0
  66. data/lib/jss/webhooks/event_objects/mobile_device.rb +47 -0
  67. data/lib/jss/webhooks/event_objects/patch_software_title_update.rb +37 -0
  68. data/lib/jss/webhooks/event_objects/push.rb +32 -0
  69. data/lib/jss/webhooks/event_objects/rest_api_operation.rb +36 -0
  70. data/lib/jss/webhooks/event_objects/scep_challenge.rb +31 -0
  71. data/lib/jss/webhooks/event_objects/smart_group.rb +34 -0
  72. data/lib/jss/webhooks/server_app.rb +36 -0
  73. data/lib/jss/webhooks/server_app/routes.rb +26 -0
  74. data/lib/jss/webhooks/server_app/routes/handle_webhook_event.rb +38 -0
  75. data/lib/jss/webhooks/server_app/routes/home.rb +36 -0
  76. data/lib/jss/webhooks/server_app/self_signed_cert.rb +64 -0
  77. data/lib/jss/webhooks/server_app/server.rb +59 -0
  78. data/lib/jss/webhooks/version.rb +31 -0
  79. metadata +63 -4
@@ -1,49 +1,42 @@
1
1
  ### Copyright 2016 Pixar
2
- ###
2
+ ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
5
5
  ### compliance with the Apache License and the following modification to it:
6
6
  ### Section 6. Trademarks. is deleted and replaced with:
7
- ###
7
+ ###
8
8
  ### 6. Trademarks. This License does not grant permission to use the trade
9
9
  ### names, trademarks, service marks, or product names of the Licensor
10
10
  ### and its affiliates, except as required to comply with Section 4(c) of
11
11
  ### the License and to reproduce the content of the NOTICE file.
12
- ###
12
+ ###
13
13
  ### You may obtain a copy of the Apache License at
14
- ###
14
+ ###
15
15
  ### http://www.apache.org/licenses/LICENSE-2.0
16
- ###
16
+ ###
17
17
  ### Unless required by applicable law or agreed to in writing, software
18
18
  ### distributed under the Apache License with the above modification is
19
19
  ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
20
  ### KIND, either express or implied. See the Apache License for the specific
21
21
  ### language governing permissions and limitations under the Apache License.
22
- ###
22
+ ###
23
23
  ###
24
24
 
25
25
  ###
26
26
  module JSS
27
27
 
28
- ######################
29
28
  ### Module Constants
30
29
  ######################
31
30
 
32
-
33
- ######################
34
31
  ### Module Variables
35
32
  ######################
36
33
 
37
- ######################
38
34
  ### Module Methods
39
35
  ######################
40
36
 
41
-
42
- #####################################
43
37
  ### Classes
44
38
  #####################################
45
39
 
46
- ###
47
40
  ### A class implementing a JSS Policy.
48
41
  ###
49
42
  ### Like many API objects, the data comes from the API in sections, and
@@ -52,8 +45,8 @@ module JSS
52
45
  ###
53
46
  ###
54
47
  ### Policy instances are partially read-only:
55
- ### - New policies cannot be created via this class, please use the WebApp.
56
- ### - Only a few attributes can be changed and updated via the Policy class:
48
+ ### - Due to limitations in the API implementation of policies, as well as the complexity
49
+ ### of policy objects, only these attributes can be set and updated via the Policy class:
57
50
  ### - - name
58
51
  ### - - frequency
59
52
  ### - - target_drive
@@ -63,21 +56,25 @@ module JSS
63
56
  ### - - triggers
64
57
  ### - - scope, see {JSS::Scopable} and {JSS::Scopable::Scope}
65
58
  ### - - files and processes
59
+ ### - - packages, see {#add_package} and {#remove_package}
60
+ ### - - scripts see {#add_script} and {#remove_script}
61
+ ### - - self service, see {JSS::SelfServable}
62
+ ###
66
63
  ### All other values and sections must be edited via the Web App.
67
64
  ###
68
65
  ### Policies may be deleted via this class
69
66
  ###
70
- ### @see JSS::APIObject
71
- ###
72
67
  class Policy < JSS::APIObject
73
68
 
74
69
  #####################################
75
70
  ### Mix-Ins
76
71
  #####################################
77
72
 
73
+ include JSS::Creatable
78
74
  include JSS::Updatable
79
75
  include JSS::Scopable
80
76
  include JSS::Uploadable
77
+ include JSS::SelfServable
81
78
 
82
79
  #####################################
83
80
  ### Class Methods
@@ -87,9 +84,8 @@ module JSS
87
84
  ### Class Constants
88
85
  #####################################
89
86
 
90
-
91
87
  ### The base for REST resources of this class
92
- RSRC_BASE = "policies"
88
+ RSRC_BASE = 'policies'.freeze
93
89
 
94
90
  ### the hash key used for the JSON list output of all objects in the JSS
95
91
  RSRC_LIST_KEY = :policies
@@ -99,8 +95,16 @@ module JSS
99
95
  RSRC_OBJECT_KEY = :policy
100
96
 
101
97
  ### these keys, as well as :id and :name, are present in valid API JSON data for this class
102
- VALID_DATA_KEYS = [:scope, :user_interaction, :files_processes ]
98
+ VALID_DATA_KEYS = [:scope, :user_interaction, :files_processes].freeze
103
99
 
100
+ ### policies can take uploaded icons
101
+ UPLOAD_TYPES = { icon: :policies }.freeze
102
+
103
+ ### policies are available in macOS self Serviec
104
+ SELF_SERVICE_TARGET = :macos
105
+
106
+ ### policies via self services are still polcies
107
+ SELF_SERVICE_PAYLOAD = :policy
104
108
 
105
109
  SECTIONS = [
106
110
  :general,
@@ -116,72 +120,89 @@ module JSS
116
120
  :dock_items,
117
121
  :disk_encryption,
118
122
  :printers
119
- ]
123
+ ].freeze
120
124
 
121
125
  FREQUENCIES = {
122
- :ongoing => "Ongoing",
123
- :once_per_computer => "Once per computer",
124
- :once_per_user =>"Once per user",
125
- :daily => "Once every day",
126
- :weekly => "Once every week",
127
- :monthly => "Once every month"
128
- }
126
+ ongoing: 'Ongoing',
127
+ once_per_computer: 'Once per computer',
128
+ once_per_user: 'Once per user',
129
+ daily: 'Once every day',
130
+ weekly: 'Once every week',
131
+ monthly: 'Once every month'
132
+ }.freeze
129
133
 
130
134
  RESTART_WHEN = {
131
- :if_pkg_requires => "Restart if a package or update requires it",
132
- :now => "Restart immediately",
133
- :delayed => "Restart",
134
- :dont => "Do not restart"
135
- }
135
+ if_pkg_requires: 'Restart if a package or update requires it',
136
+ now: 'Restart immediately',
137
+ delayed: 'Restart',
138
+ dont: 'Do not restart'
139
+ }.freeze
136
140
 
137
141
  RESTART_DISKS = {
138
- :current => "Current Startup Disk",
139
- :selected => "Currently Selected Startup Disk (No Bless)",
140
- :netboot => "NetBoot",
141
- :os_installer => "inPlaceOSUpgradeDirectory"
142
- } # Note: any other value in :specify_startup is a path to some other drive to boot from, e.g. /Volumes/Foo
142
+ current: 'Current Startup Disk',
143
+ selected: 'Currently Selected Startup Disk (No Bless)',
144
+ netboot: 'NetBoot',
145
+ os_installer: 'inPlaceOSUpgradeDirectory'
146
+ }.freeze # Note: any other value in :specify_startup is a path to some other drive to boot from, e.g. /Volumes/Foo
143
147
 
144
148
  ACCOUNT_ACTIONS = {
145
- :create => "Create",
146
- :change_pw => "Reset",
147
- :delete => "Delete",
148
- :disable_fv2 => "DisableFileVault"
149
- }
149
+ create: 'Create',
150
+ change_pw: 'Reset',
151
+ delete: 'Delete',
152
+ disable_fv2: 'DisableFileVault'
153
+ }.freeze
150
154
 
151
155
  MGMT_ACCOUNT_ACTIONS = {
152
- :no_change => "doNotChange",
153
- :change_pw => "specified",
154
- :generate_pw => "random",
155
- :enable_fv2 => "fileVaultEnable",
156
- :disable_fv2 => "fileVaultDisable"
157
- }
156
+ no_change: 'doNotChange',
157
+ change_pw: 'specified',
158
+ generate_pw: 'random',
159
+ enable_fv2: 'fileVaultEnable',
160
+ disable_fv2: 'fileVaultDisable'
161
+ }.freeze
158
162
 
159
163
  PACKAGE_ACTIONS = {
160
- :install => "Install",
161
- :remove => "Uninstall",
162
- :cache =>"Cache",
163
- :install_cache => "Install Cached"
164
- }
165
-
166
- SCRIPT_PRIORITIES = {:pre => "Before", :post => "After"}
167
-
168
- PRINTER_ACTIIONS = {:map => "install", :unmap => "uninstall"}
169
-
170
- DOCK_ITEM_ACTIONS = {:add_start => "Add To Beginning", :add_end => "Add To End", :remove => "Remove"}
171
-
172
- NETWORK_REQUIREMENTS = {:any => "Any", :ethernet => "EtherNet"}
164
+ install: 'Install',
165
+ remove: 'Uninstall',
166
+ cache: 'Cache',
167
+ install_cache: 'Install Cached'
168
+ }.freeze
169
+
170
+ SCRIPT_PRIORITIES = {
171
+ pre: 'Before',
172
+ before: 'Before',
173
+ post: 'After',
174
+ after: 'After'
175
+ }.freeze
176
+
177
+ PRINTER_ACTIIONS = {
178
+ map: 'install',
179
+ unmap: 'uninstall'
180
+ }.freeze
181
+
182
+ DOCK_ITEM_ACTIONS = {
183
+ add_start: 'Add To Beginning',
184
+ add_end: 'Add To End', remove: 'Remove'
185
+ }.freeze
186
+
187
+ NETWORK_REQUIREMENTS = {
188
+ any: 'Any',
189
+ ethernet: 'EtherNet'
190
+ }.freeze
191
+
192
+ TRIGGER_TYPES = {
193
+ event: 'EVENT',
194
+ user: 'USER_INITIATED'
195
+ }.freeze
173
196
 
174
197
  TRIGGER_EVENTS = {
175
- :startup => :trigger_startup,
176
- :login => :trigger_login,
177
- :logout => :trigger_logout,
178
- :checkin => :trigger_checkin,
179
- :network_state => :trigger_network_state_changed ,
180
- :enrollment => :trigger_enrollment_complete ,
181
- :custom => :trigger_other
182
- }
183
-
184
- TRIGGER_TYPES = {:event => "EVENT", :user => "USER_INITIATED"}
198
+ startup: :trigger_startup,
199
+ login: :trigger_login,
200
+ logout: :trigger_logout,
201
+ checkin: :trigger_checkin,
202
+ network_state: :trigger_network_state_changed,
203
+ enrollment: :trigger_enrollment_complete,
204
+ custom: :trigger_other
205
+ }.freeze
185
206
 
186
207
  SCOPE_TARGET_KEY = :computers
187
208
 
@@ -213,12 +234,27 @@ module JSS
213
234
  ### @return [String] a string with the site name
214
235
  attr_reader :site
215
236
 
216
-
217
237
  ### @return [Hash]
218
238
  ###
219
239
  ### Overrides for various defaults
220
240
  ###
221
- ### The hash looks like: !{ :distribution_point => "", :force_afp_smb => false, :netboot_server => "current", :target_drive => "default", :sus => "default"}
241
+ ### NOTE: There's an API bug in both XML and JSON with the
242
+ ### :distribution_point and :target_drive values.
243
+ ### First off, it's not clear what the :target_drive value here
244
+ ### is overriding, since there's a :target_drive value in the
245
+ ### main General hash.
246
+ ### Second off - when you set a non-default dist.point in the
247
+ ### packages section of the UI, that value shows up in both
248
+ ### this :target_drive and the general one, but the :distribution_point
249
+ ### value here stays empty.
250
+ ###
251
+ ### The hash looks like:
252
+ ### :distribution_point => "",
253
+ ### :force_afp_smb => false,
254
+ ### :netboot_server => "current",
255
+ ### :target_drive => "default",
256
+ ### :sus => "default"
257
+ ###
222
258
  attr_reader :override_default_settings
223
259
 
224
260
  ### The API has a :network_requirements key in the general section, but
@@ -304,10 +340,11 @@ module JSS
304
340
  ###
305
341
  attr_reader :trigger_events
306
342
 
307
- ##### client machine maintenence
343
+ ###### client machine maintenence
308
344
  ### These are the computer maint. tasks
309
345
  ### that might be performed by this policy
310
346
  ### All are boolean
347
+ ### TODO: make individial getters/setters as for @files_processes
311
348
 
312
349
  ### @return [Boolean] client maintenance task
313
350
  attr_reader :verify_startup_disk
@@ -333,20 +370,14 @@ module JSS
333
370
  ### @return [Boolean] client maintenance task
334
371
  attr_reader :flush_user_cache
335
372
 
336
- ### attr_reader :heal # deprecated
337
- ### attr_reader :prebinding # deprecated
338
-
339
- ##### client account maint
340
- ### acct related maintenence performed by this policy
341
-
342
373
  ### @return [Array<Hash>]
343
374
  ###
344
375
  ### The directory bindings applied
345
376
  ###
346
377
  ### each hash is like: !{:name => "LDAP", :id => 4}
378
+ ### TODO: handle as for packages & scripts
347
379
  attr_reader :directory_bindings
348
380
 
349
-
350
381
  ### @return [Hash] the open firmware mode and password
351
382
  attr_reader :open_firmware_efi_password
352
383
 
@@ -361,6 +392,7 @@ module JSS
361
392
  ### - :managed_password_sha256
362
393
  ### - :managed_password_length # for random generating pws
363
394
  ###
395
+ ### TODO: make individial getters/setters as for @files_processes
364
396
  attr_reader :management_account
365
397
 
366
398
  ### @return [Array<Hash>]
@@ -377,9 +409,10 @@ module JSS
377
409
  ### - :filevault_enabled => true,
378
410
  ### - :username => "chrisltest",
379
411
  ### - :password_md5 => "3858f62230ac3c915f300c664312c63f",
380
- ### - : password => "foobar",
412
+ ### - :password => "foobar",
381
413
  ### - :password_sha256=> "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"
382
414
  ###
415
+ ### TODO: make individial getters/setters as for @files_processes
383
416
  attr_reader :accounts
384
417
 
385
418
  ### @return [Array<Hash>]
@@ -414,23 +447,7 @@ module JSS
414
447
  ###
415
448
  attr_reader :scripts
416
449
 
417
-
418
- ### @return [Hash]
419
- ###
420
- ### Self-service-related data for this policy
421
- ###
422
- ### The hash keys are:
423
- ### - :self_service_icon => !{:uri => String,:id => Integer, :filename => String}
424
- ### - :use_for_self_service => true,
425
- ### - :install_button_text => "Install",
426
- ### - :self_service_description => "Descriptive text",
427
- ### - :force_users_to_view_description => false
428
- ###
429
- ### Note: we'll add a ruby-std convenience method below "self_service?"
430
- ### which returns the :use_for_self_service key.
431
- attr_reader :self_service
432
-
433
- #### user interaction
450
+ ###### user interaction
434
451
  ### These are extracted from the :user_interaction hash
435
452
  ### in the JSON output, which looks like this:
436
453
  ### :message_start => "",
@@ -438,6 +455,7 @@ module JSS
438
455
  ### :allow_deferral_until_utc => "",
439
456
  ### :message_finish => ""
440
457
  ###
458
+ ### TODO: make individial getters/setters as for @files_processes
441
459
 
442
460
  ### @return [Boolean] can the user defer the policy?
443
461
  attr_reader :user_may_defer
@@ -458,11 +476,13 @@ module JSS
458
476
  ### The hash keys are:
459
477
  ### - :user_logged_in => "Do not restart",
460
478
  ### - :minutes_until_reboot => 5,
461
- ### - :message=> "This computer will restart in 5 minutes. Please save anything you are working on and log out by choosing Log Out from the bottom of the Apple menu.",
479
+ ### - :message=> "This computer will restart in 5 minutes. yaddayadda.",
462
480
  ### - :startup_disk => "Current Startup Disk",
463
481
  ### - :specify_startup => "",
464
482
  ### - :no_user_logged_in => "Do not restart"
483
+ ### - :file_vault_2_reboot => false
465
484
  ###
485
+ ### TODO: make individial getters/setters as for @files_processes
466
486
  attr_reader :reboot_options
467
487
 
468
488
  ##### files & processes
@@ -480,7 +500,6 @@ module JSS
480
500
  ### so that the hash isn't directly changable without @need_to_update.
481
501
  ### attr_reader :files_processes
482
502
 
483
-
484
503
  ### @return [Array<Hash>]
485
504
  ###
486
505
  ### The dock items handled by this policy
@@ -506,150 +525,186 @@ module JSS
506
525
  ### Public Instance Methods
507
526
  #####################################
508
527
 
509
- ###
510
528
  ### @see APIObject#initialize
511
529
  ###
512
530
  def initialize(args = {})
513
-
514
531
  super
515
532
 
533
+ if @in_jss
534
+ gen = @init_data[:general]
535
+ @category = JSS::APIObject.get_name(gen[:category])
536
+ @frequency = gen[:frequency]
537
+ @target_drive = gen[:target_drive]
538
+ @offline = gen[:offline]
539
+ @enabled = gen[:enabled]
540
+ @site = JSS::APIObject.get_name(gen[:site][:name])
541
+ @override_default_settings = gen[:override_default_settings]
542
+ @trigger = gen[:trigger]
543
+ @trigger_events = {
544
+ trigger_startup: gen[:trigger_startup],
545
+ trigger_login: gen[:trigger_login],
546
+ trigger_logout: gen[:trigger_logout],
547
+ trigger_checkin: gen[:trigger_checkin],
548
+ trigger_network_state_changed: gen[:trigger_network_state_changed],
549
+ trigger_enrollment_complete: gen[:trigger_enrollment_complete],
550
+ trigger_other: gen[:trigger_other]
551
+ }
552
+
553
+ dtl = gen[:date_time_limitations]
554
+
555
+ @server_side_limitations = {
556
+ activation: JSS.epoch_to_time(dtl[:activation_date_epoch]),
557
+ expiration: JSS.epoch_to_time(dtl[:expiration_date_epoch])
558
+ }
559
+
560
+ @client_side_limitations = {
561
+ no_execute_on: dtl[:no_execute_on], # NOTE- there's a bug in the JSON output, it's been reported to JAMF.
562
+ no_execute_start: dtl[:no_execute_start], # String like "1:01 AM"
563
+ no_execute_end: dtl[:no_execute_end], # String like "2:02 PM"
564
+ network_requirements: gen[:network_requirements]
565
+ }
566
+
567
+ maint = @init_data[:maintenance]
568
+ @verify_startup_disk = maint[:verify]
569
+ @permissions_repair = maint[:permissions]
570
+ @recon = maint[:recon]
571
+ @fix_byhost = maint[:byhost]
572
+ @reset_name = maint[:reset_name]
573
+ @flush_system_cache = maint[:system_cache]
574
+ @install_cached_pkgs = maint[:install_all_cached_packages]
575
+ @flush_user_cache = maint[:user_cache]
576
+
577
+ amaint = @init_data[:account_maintenance]
578
+ @directory_bindings = amaint[:directory_bindings]
579
+ @open_firmware_efi_password = amaint[:open_firmware_efi_password]
580
+ @management_account = amaint[:management_account]
581
+ @accounts = amaint[:accounts]
582
+
583
+ @packages = @init_data[:package_configuration][:packages] ? @init_data[:package_configuration][:packages] : []
584
+
585
+ @scripts = @init_data[:scripts]
586
+
587
+ uint = @init_data[:user_interaction]
588
+ @user_may_defer = uint[:allow_users_to_defer]
589
+ @user_may_defer_until = JSS.parse_datetime uint[:allow_deferral_until_utc]
590
+ @user_message_start = uint[:message_start]
591
+ @user_message_finish = uint[:message_finish]
592
+
593
+ @reboot_options = @init_data[:reboot]
594
+
595
+ @files_processes = @init_data[:files_processes]
596
+
597
+ @dock_items = @init_data[:dock_items]
598
+
599
+ @disk_encryption = @init_data[:disk_encryption]
600
+
601
+ @printers = @init_data[:printers]
602
+
603
+ parse_scope
604
+ parse_self_service
605
+ @in_self_service = @init_data[:self_service][:use_for_self_service]
606
+
607
+ ### Not in jss yet
608
+ end
516
609
 
517
- gen = @init_data[:general]
518
- @category = JSS::APIObject.get_name(gen[:category])
519
- @frequency = gen[:frequency]
520
- @target_drive = gen[:target_drive]
521
- @offline = gen[:offline]
522
- @enabled = gen[:enabled]
523
- @site = JSS::APIObject.get_name(gen[:site][:name])
524
- @override_default_settings = gen[:override_default_settings]
525
- @trigger = gen[:trigger ]
526
- @trigger_events = {
527
- :trigger_startup => gen[:trigger_startup ],
528
- :trigger_login => gen[:trigger_login ],
529
- :trigger_logout => gen[:trigger_logout ],
530
- :trigger_checkin => gen[:trigger_checkin ],
531
- :trigger_network_state_changed => gen[:trigger_network_state_changed ],
532
- :trigger_enrollment_complete => gen[:trigger_enrollment_complete ],
533
- :trigger_other => gen[:trigger_other ]
534
- }
535
-
536
- dtl = gen[:date_time_limitations]
537
-
538
- @server_side_limitations = {
539
- :activation => JSS.epoch_to_time(dtl[:activation_date_epoch]),
540
- :expiration => JSS.epoch_to_time(dtl[:expiration_date_epoch])
541
- }
542
-
543
- @client_side_limitations = {
544
- :no_execute_on => dtl[:no_execute_on], # NOTE- there's a bug in the JSON output, it's been reported to JAMF.
545
- :no_execute_start => dtl[:no_execute_start], # String like "1:01 AM"
546
- :no_execute_end => dtl[:no_execute_end], # String like "2:02 PM"
547
- :network_requirements => gen[:network_requirements]
548
- }
549
-
550
- maint = @init_data[:maintenance]
551
- @verify_startup_disk = maint[:verify]
552
- @permissions_repair = maint[:permissions]
553
- @recon = maint[:recon]
554
- @fix_byhost = maint[:byhost]
555
- @reset_name = maint[:reset_name]
556
- @flush_system_cache = maint[:system_cache]
557
- @install_cached_pkgs = maint[:install_all_cached_packages]
558
- @flush_user_cache = maint[:user_cache]
559
-
560
- amaint = @init_data[:account_maintenance]
561
- @directory_bindings = amaint[:directory_bindings]
562
- @open_firmware_efi_password = amaint[:open_firmware_efi_password]
563
- @management_account = amaint[:management_account]
564
- @accounts = amaint[:accounts]
565
-
566
- @packages = @init_data[:package_configuration][:packages] ? @init_data[:package_configuration][:packages] : []
567
-
568
- @scripts = @init_data[:scripts]
569
-
570
- @self_service = @init_data[:self_service]
571
-
572
- uint = @init_data[:user_interaction]
573
- @user_may_defer = uint[:allow_users_to_defer]
574
- @user_may_defer_until = JSS.parse_datetime uint[:allow_deferral_until_utc]
575
- @user_message_start = uint[:message_start]
576
- @user_message_finish = uint[:message_finish]
577
-
578
- @reboot_options = @init_data[:reboot]
579
-
580
- @files_processes = @init_data[:files_processes]
581
-
582
- @dock_items = @init_data[:dock_items]
583
-
584
- @disk_encryption = @init_data[:disk_encryption]
585
-
586
- @printers = @init_data[:printers]
610
+ # set non-nil defaults
611
+ @enabled ||= false
612
+ @frequency ||= 'Once per computer'
613
+ @target_drive ||= '/'
614
+ @offline ||= false
615
+ @override_default_settings ||= {}
616
+ @scripts ||= []
617
+ @server_side_limitations ||= {}
618
+ @client_side_limitiations ||= {}
619
+ @trigger_events ||= {}
620
+ @directory_bindings ||= []
621
+ @open_firmware_efi_password ||= {}
622
+ @management_account ||= {}
623
+ @accounts ||= []
624
+ @packages ||= []
625
+ @scripts ||= []
626
+ @self_service ||= {}
627
+ @dock_items ||= []
628
+ @disk_encryption ||= {}
629
+ @printers ||= []
630
+ @files_processes ||= {}
631
+ unless @reboot_options
632
+ @reboot_options = {}
633
+ @reboot_options[:user_logged_in] = 'Do not restart'
634
+ @reboot_options[:no_user_logged_in] = 'Do not restart'
635
+ end
587
636
 
588
- parse_scope
637
+ @scope ||= JSS::Scopable::Scope.new(:computers, all_computers: false)
638
+ end # init
589
639
 
590
- end # init
640
+ ###### General
591
641
 
592
- ###
593
642
  ### Change the enabled state of this item
594
643
  ###
595
644
  ### @param new_val[Boolean] the new state.
596
645
  ###
597
646
  ### @return [void]
598
647
  ###
599
- def enabled= (new_val)
648
+ def enabled=(new_val)
600
649
  return nil if @enabled == new_val
601
- raise JSS::InvalidDataError, "New value must be true or false" unless JSS::TRUE_FALSE.include? new_val
650
+ raise JSS::InvalidDataError, 'New value must be true or false' unless JSS::TRUE_FALSE.include? new_val
602
651
  @enabled = new_val
603
652
  @need_to_update = true
604
653
  end
605
654
 
606
- ###
655
+ ### Shortcut for enabled = true
656
+ def enable
657
+ self.enabled = true
658
+ end
659
+
660
+ ### Shortcut for endabled = false
661
+ def disable
662
+ self.enabled = false
663
+ end
664
+
607
665
  ### Set a new frequency for this policy.
608
666
  ###
609
667
  ### @param freq[Symbol] the desired frequency, must be one of the keys of {FREQUENCIES}
610
668
  ###
611
669
  ### @return [void]
612
670
  ###
613
- def frequency= (freq)
614
- raise JSS::InvalidDataError, "New frequency must be one of :#{FREQUENCIES.keys.join ", :"}" unless FREQUENCIES.keys.include? freq
671
+ def frequency=(freq)
672
+ raise JSS::InvalidDataError, "New frequency must be one of :#{FREQUENCIES.keys.join ', :'}" unless FREQUENCIES.keys.include? freq
615
673
  @frequency = FREQUENCIES[freq]
616
674
  @need_to_update = true
617
675
  end
618
676
 
619
- ###
620
677
  ### Set a new target drive for this policy.
621
678
  ###
622
679
  ### @param path_to_drive[String,Pathname] the full path to the target drive, must start with a '/'
623
680
  ###
624
681
  ### @return [void]
625
682
  ###
626
- def target_drive= (path_to_drive)
627
- raise JSS::InvalidDataError, "Path to target drive must be absolute" unless path_to_drive.to_s.start_with? '/'
683
+ def target_drive=(path_to_drive)
684
+ raise JSS::InvalidDataError, 'Path to target drive must be absolute' unless path_to_drive.to_s.start_with? '/'
628
685
  @target_drive = path_to_drive.to_s
629
686
  @need_to_update = true
630
687
  end
631
688
 
632
- ###
633
689
  ### Set whether this policy is available offline.
634
690
  ###
635
691
  ### @param new_val[Boolean]
636
692
  ###
637
693
  ### @return [void]
638
694
  ###
639
- def offline= (new_val)
640
- raise JSS::InvalidDataError, "New value must be boolean true or false" unless JSS::TRUE_FALSE.include? new_val
695
+ def offline=(new_val)
696
+ raise JSS::InvalidDataError, 'New value must be boolean true or false' unless JSS::TRUE_FALSE.include? new_val
641
697
  @offline = new_val
642
698
  @need_to_update = true
643
699
  end
644
700
 
645
- ###
646
- ### Change the category of this item, arg is a category name
701
+ ### Change the category of this policy, arg is a category name
647
702
  ###
648
703
  ### @param new_val[String] the name of the new category
649
704
  ###
650
705
  ### @return [void]
651
706
  ###
652
- def category= (new_val = JSS::Category::DEFAULT_CATEGORY)
707
+ def category=(new_val = JSS::Category::DEFAULT_CATEGORY)
653
708
  return nil if @category == new_val
654
709
  new_val = nil if new_val == ''
655
710
  new_val ||= JSS::Category::DEFAULT_CATEGORY
@@ -658,7 +713,6 @@ module JSS
658
713
  @need_to_update = true
659
714
  end
660
715
 
661
- ###
662
716
  ### Change a trigger event
663
717
  ###
664
718
  ### @param type[Symbol] the type of trigger, one of the keys of {TRIGGER_EVENTS}
@@ -667,67 +721,66 @@ module JSS
667
721
  ###
668
722
  ### @return [void]
669
723
  ###
670
- def set_trigger_event (type, new_val)
724
+ def set_trigger_event(type, new_val)
671
725
  raise JSS::InvalidDataError, "Trigger type must be one of #{TRIGGER_EVENTS.keys.join(', ')}" unless TRIGGER_EVENTS.keys.include? type
672
726
  if type == :custom
673
- raise JSS::InvalidDataError, "Custom triggers must be Strings" unless new_val.kind_of? String
727
+ raise JSS::InvalidDataError, 'Custom triggers must be Strings' unless new_val.is_a? String
674
728
  else
675
- raise JSS::InvalidDataError, "Non-custom triggers must be true or false" unless JSS::TRUE_FALSE.include? new_val
729
+ raise JSS::InvalidDataError, 'Non-custom triggers must be true or false' unless JSS::TRUE_FALSE.include? new_val
676
730
  end
677
731
  @trigger_events[TRIGGER_EVENTS[type]] = new_val
678
732
  @need_to_update = true
679
733
  end
680
734
 
681
- ###
735
+ ###### Files & Processes
736
+
682
737
  ### @return [String] The unix shell command to run on ths client.
683
738
  ###
684
- def run_command ; @files_processes[:run_command] ; end
739
+ def run_command
740
+ @files_processes[:run_command]
741
+ end
685
742
 
686
- ###
687
743
  ### Set the unix shell command to be run on the client
688
744
  ###
689
745
  ### @param command[String] the unix shell command to be run on the client
690
746
  ###
691
747
  ### @return [void]
692
748
  ###
693
- def run_command= (command)
694
- raise JSS::InvalidDataError, "Command to run must be a String" unless command.is_a? String
749
+ def run_command=(command)
750
+ raise JSS::InvalidDataError, 'Command to run must be a String' unless command.is_a? String
695
751
  @files_processes[:run_command] = command
696
752
  @need_to_update = true
697
753
  end
698
754
 
699
- ###
700
755
  ### @return [Boolean] Should we update the database used by the locate command?
701
756
  ###
702
- def update_locate_database? ; @files_processes[:update_locate_database] ; end
757
+ def update_locate_database?
758
+ @files_processes[:update_locate_database]
759
+ end
703
760
 
704
- ###
705
761
  ### Set whether or not to update the database used by the locate command.
706
762
  ###
707
763
  ### @param tf[Boolean] whether or not to update the database used by the locate command.
708
764
  ###
709
765
  ### @return [void]
710
766
  ###
711
- def update_locate_database= (tf)
767
+ def update_locate_database=(tf)
712
768
  @files_processes[:update_locate_database] = tf ? true : false
713
769
  @need_to_update = true
714
770
  end
715
771
 
716
- ###
717
772
  ### @return [String] The process name to search for on the client
718
773
  ###
719
774
  def search_for_process
720
775
  @files_processes[:search_for_process]
721
776
  end
722
777
 
723
- ###
724
778
  ### @return [Boolean] Should the searched-for process be killed if found.
725
779
  ###
726
780
  def kill_process?
727
781
  @files_processes[:kill_process]
728
782
  end
729
783
 
730
- ###
731
784
  ### Set the process name to search for, and if it should be killed if found.
732
785
  ###
733
786
  ### Setter methods (which end with =) can't easily take
@@ -740,23 +793,24 @@ module JSS
740
793
  ###
741
794
  ### @return [void]
742
795
  ###
743
- def set_search_for_process (process, kill = false)
796
+ def set_search_for_process(process, kill = false)
744
797
  @files_processes[:search_for_process] = process.to_s
745
798
  @files_processes[:kill_process] = kill ? true : false
746
799
  @need_to_update = true
747
800
  end
748
801
 
749
- ###
750
802
  ### @return [Pathname] The path to search for
751
803
  ###
752
- def search_by_path ; Pathname.new @files_processes[:search_by_path] ; end
804
+ def search_by_path
805
+ Pathname.new @files_processes[:search_by_path]
806
+ end
753
807
 
754
- ###
755
808
  ### @return [Boolean] Should the searched-for path be deleted if found?
756
809
  ###
757
- def delete_file? ; @files_processes[:delete_file] ; end
810
+ def delete_file?
811
+ @files_processes[:delete_file]
812
+ end
758
813
 
759
- ###
760
814
  ### Set the path to search for, a String or Pathname, and whether or not to delete it if found.
761
815
  ###
762
816
  ### Setter methods (which end with =) can't easily take
@@ -769,17 +823,18 @@ module JSS
769
823
  ###
770
824
  ### @return [void]
771
825
  ###
772
- def set_search_by_path (path, delete = false)
773
- raise JSS::InvalidDataError, "Path to search for must be a String or a Pathname" unless path.is_a? String or path.is_a? Pathname
826
+ def set_search_by_path(path, delete = false)
827
+ raise JSS::InvalidDataError, 'Path to search for must be a String or a Pathname' unless path.is_a?(String) || path.is_a?(Pathname)
774
828
  @files_processes[:search_by_path] = path.to_s
775
829
  @files_processes[:delete_file] = delete ? true : false
776
830
  @need_to_update = true
777
831
  end
778
832
 
779
- ###
780
833
  ### @return [String] The term to search for using spotlight
781
834
  ###
782
- def spotlight_search ; @files_processes[:spotlight_search] ; end
835
+ def spotlight_search
836
+ @files_processes[:spotlight_search]
837
+ end
783
838
 
784
839
  ### Set the term to seach for using spotlight
785
840
  ###
@@ -787,16 +842,17 @@ module JSS
787
842
  ###
788
843
  ### @return [void]
789
844
  ###
790
- def spotlight_search= (term)
791
- raise JSS::InvalidDataError, "Spotlight search term must be a String" unless term.is_a? String
845
+ def spotlight_search=(term)
846
+ raise JSS::InvalidDataError, 'Spotlight search term must be a String' unless term.is_a? String
792
847
  @files_processes[:spotlight_search] = term
793
848
  @need_to_update = true
794
849
  end
795
850
 
796
- ###
797
851
  ### @return [String] The term to seach for using the locate command
798
852
  ###
799
- def locate_file ; @files_processes[:locate_file] ; end
853
+ def locate_file
854
+ @files_processes[:locate_file]
855
+ end
800
856
 
801
857
  ### Set the term to seach for using the locate command
802
858
  ###
@@ -804,68 +860,333 @@ module JSS
804
860
  ###
805
861
  ### @return [void]
806
862
  ###
807
- def locate_file= (term)
808
- raise JSS::InvalidDataError, "Term to locate must be a String" unless term.is_a? String
863
+ def locate_file=(term)
864
+ raise JSS::InvalidDataError, 'Term to locate must be a String' unless term.is_a? String
809
865
  @files_processes[:locate_file] = term
810
866
  @need_to_update = true
811
867
  end
812
868
 
869
+ ###### Client maintenance
870
+
871
+ ### Set the
872
+
873
+ ###### Packages
874
+
813
875
  ### @return [Array] the id's of the packages handled by the policy
814
- def package_ids; @packages.map{|p| p[:id]} ; end
876
+ def package_ids
877
+ @packages.map { |p| p[:id] }
878
+ end
815
879
 
816
880
  ### @return [Array] the names of the packages handled by the policy
817
- def package_names; @packages.map{|p| p[:name]} ; end
881
+ def package_names
882
+ @packages.map { |p| p[:name] }
883
+ end
884
+
885
+ ### Add a package to the list of pkgs handled by this policy.
886
+ ### If the pkg already exists in the policy, nil is returned and
887
+ ### no changes are made.
888
+ ###
889
+ ### @param [String,Integer] identifier the name or id of the package to add to this policy
890
+ ###
891
+ ### @param [Hash] opts the options for this pkg
892
+ ###
893
+ ### @option [Symbol, Integer] position: :end where to add this pkg among the list of
894
+ ### pkgs. Zero-based, :start and 0 are the same, as are :end and -1. Defaults to :end
895
+ ###
896
+ ### @option [String] action: 'Install' One of the values of PACKAGE_ACTIONS
897
+ ###
898
+ ### @option [Boolean] feu: false Overrides the setting for the pkg itself
899
+ ###
900
+ ### @option [Boolean] fut: false Overrides the setting for the pkg itself
901
+ ###
902
+ ### @option [Boolean] update_autorun: false
903
+ ###
904
+ ### @return [Array, nil] the new @packages array, nil if pkg was already in the policy
905
+ ###
906
+ def add_package(identifier, opts = {})
907
+ opts[:position] ||= -1
908
+ opts[:action] ||= :install
909
+ opts[:feu] = false if opts[:feu].nil?
910
+ opts[:fut] = false if opts[:fut].nil?
911
+ opts[:update_autorun] = false if opts[:update_autorun].nil?
912
+
913
+ id = JSS::Package.valid_id identifier
914
+ raise JSS::NoSuchItemError, "No package matches '#{identifier}'" unless id
915
+
916
+ return nil if @packages.map { |p| p[:id] }.include? id
917
+
918
+ name = JSS::Package.map_all_ids_to(:name)[id]
919
+
920
+ position = case opts[:position]
921
+ when :start then 0
922
+ when :end then -1
923
+ else opts[:position]
924
+ end
925
+
926
+ raise JSS::InvalidDataError, "action must be one of: :#{PACKAGE_ACTIONS.keys.join ', :'}" unless \
927
+ PACKAGE_ACTIONS.include? opts[:action]
928
+ raise JSS::InvalidDataError, 'feu must be true or false' unless \
929
+ JSS::TRUE_FALSE.include? opts[:feu]
930
+ raise JSS::InvalidDataError, 'fut must be true or false' unless \
931
+ JSS::TRUE_FALSE.include? opts[:fut]
932
+ raise JSS::InvalidDataError, 'update_autorun must be true or false' unless \
933
+ JSS::TRUE_FALSE.include? opts[:update_autorun]
934
+
935
+ pkg_data = {
936
+ id: id,
937
+ name: name,
938
+ action: PACKAGE_ACTIONS[opts[:action]],
939
+ feu: opts[:feu],
940
+ fut: opts[:feu],
941
+ update_autorun: opts[:update_autorun]
942
+ }
943
+
944
+ @packages.insert position, pkg_data
945
+
946
+ ### if the user gave a large number for position, it created nil entries in the array, they need
947
+ ### to be removed.
948
+ @packages.compact!
949
+
950
+ @need_to_update = true
951
+ @packages
952
+ end
953
+
954
+ ### Remove a package from this policy by name or id
955
+ ###
956
+ ### @param identfier [String,Integer] the name or id of the package to remove
957
+ ###
958
+ ### @return [Array, nil] the new packages array or nil if no change
959
+ ###
960
+ def remove_package(identifier)
961
+ removed = @packages.delete_if { |p| p[:id] == identifier || p[:name] == identifier }
962
+ @need_to_update = true if removed
963
+ removed
964
+ end
965
+
966
+ ###### Scripts
818
967
 
819
968
  ### @return [Array] the id's of the scripts handled by the policy
820
- def script_ids; @scripts.map{|p| p[:id]} ; end
969
+ def script_ids
970
+ @scripts.map { |p| p[:id] }
971
+ end
821
972
 
822
973
  ### @return [Array] the names of the scripts handled by the policy
823
- def script_names; @scripts.map{|p| p[:name]} ; end
974
+ def script_names
975
+ @scripts.map { |p| p[:name] }
976
+ end
977
+
978
+ ### Add a script to the list of SCRIPT_PRIORITIESipts run by this policy.
979
+ ### If the script already exists in the policy, nil is returned and
980
+ ### no changes are made.
981
+ ###
982
+ ### @param [String,Integer] identifier the name or id of the script to add to this policy
983
+ ###
984
+ ### @param [Hash] opts the options for this script
985
+ ###
986
+ ### @option [Symbol, Integer] position: where to add this script among the list of
987
+ ### scripts. Zero-based, :start and 0 are the same, as are :end and -1. Defaults to :end
988
+ ###
989
+ ### @option [Symbol] priority: either :before or :after
990
+ ###
991
+ ### @option [String] parameter4: the value of the 4th parameter passed to the script. this
992
+ ### overrides the same parameter in the script object itself.
993
+ ###
994
+ ### @option [String] parameter5: the value of the 5th parameter passed to the script. this
995
+ ### overrides the same parameter in the script object itself.
996
+ ###
997
+ ### @option [String] parameter6: the value of the 6th parameter passed to the script. this
998
+ ### overrides the same parameter in the script object itself.
999
+ ###
1000
+ ### @option [String] parameter7: the value of the 7th parameter passed to the script. this
1001
+ ### overrides the same parameter in the script object itself.
1002
+ ###
1003
+ ### @option [String] parameter8: the value of the 8th parameter passed to the script. this
1004
+ ### overrides the same parameter in the script object itself.
1005
+ ###
1006
+ ### @option [String] parameter9: the value of the 9th parameter passed to the script. this
1007
+ ### overrides the same parameter in the script object itself.
1008
+ ###
1009
+ ### @option [String] parameter10: the value of the 10th parameter passed to the script. this
1010
+ ### overrides the same parameter in the script object itself.
1011
+ ###
1012
+ ### @option [String] parameter11: the value of the 11th parameter passed to the script. this
1013
+ ### overrides the same parameter in the script object itself.
1014
+ ###
1015
+ ### @return [Array, nil] the new @scripts array, nil if script was already in the policy
1016
+ ###
1017
+ def add_script(identifier, opts = {})
1018
+ opts[:position] ||= -1
1019
+ opts[:priority] ||= :after
1020
+
1021
+ raise JSS::NoSuchItemError, "No script matches '#{identifier}'" unless (id = JSS::Script.valid_id(identifier))
1022
+
1023
+ return nil if @scripts.map { |s| s[:id] }.include? id
1024
+
1025
+ name = JSS::Script.map_all_ids_to(:name)[id]
1026
+
1027
+ position = case opts[:position]
1028
+ when :start then 0
1029
+ when :end then -1
1030
+ else opts[:position]
1031
+ end
1032
+
1033
+ raise JSS::InvalidDataError, "priority must be one of: :#{SCRIPT_PRIORITIES.keys.join ', :'}" unless \
1034
+ SCRIPT_PRIORITIES.include? opts[:priority]
1035
+
1036
+ script_data = {
1037
+ id: id,
1038
+ name: name,
1039
+ priority: SCRIPT_PRIORITIES[opts[:priority]],
1040
+ parameter4: opts[:parameter4],
1041
+ parameter5: opts[:parameter5],
1042
+ parameter6: opts[:parameter6],
1043
+ parameter7: opts[:parameter7],
1044
+ parameter8: opts[:parameter8],
1045
+ parameter9: opts[:parameter9],
1046
+ parameter10: opts[:parameter10],
1047
+ parameter11: opts[:parameter11]
1048
+ }
1049
+
1050
+ @scripts.insert position, script_data
1051
+
1052
+ ### if the user gave a large number for position, it created nil entries in the array, they need
1053
+ ### to be removed.
1054
+ @scripts.compact!
1055
+
1056
+ @need_to_update = true
1057
+ @scripts
1058
+ end
1059
+
1060
+ ### Remove a script from this policy by name or id
1061
+ ###
1062
+ ### @param identfier [String,Integer] the name or id of the script to remove
1063
+ ###
1064
+ ### @return [Array, nil] the new scripts array or nil if no change
1065
+ ###
1066
+ def remove_script(identifier)
1067
+ removed = @scripts.delete_if { |s| s[:id] == identifier || s[:name] == identifier }
1068
+ @need_to_update = true if removed
1069
+ removed
1070
+ end
1071
+
1072
+ ###### Directory Bindings
824
1073
 
825
1074
  ### @return [Array] the id's of the directory_bindings handled by the policy
826
- def directory_binding_ids; @directory_bindings.map{|p| p[:id]} ; end
1075
+ def directory_binding_ids
1076
+ @directory_bindings.map { |p| p[:id] }
1077
+ end
827
1078
 
828
1079
  ### @return [Array] the names of the directory_bindings handled by the policy
829
- def directory_binding_names; @directory_bindings.map{|p| p[:name]} ; end
1080
+ def directory_binding_names
1081
+ @directory_bindings.map { |p| p[:name] }
1082
+ end
1083
+
1084
+ ###### Dock items
830
1085
 
831
1086
  ### @return [Array] the id's of the dock_items handled by the policy
832
- def dock_item_ids; @dock_items.map{|p| p[:id]} ; end
1087
+ def dock_item_ids
1088
+ @dock_items.map { |p| p[:id] }
1089
+ end
833
1090
 
834
1091
  ### @return [Array] the names of the dock_items handled by the policy
835
- def dock_item_names; @dock_items.map{|p| p[:name]} ; end
1092
+ def dock_item_names
1093
+ @dock_items.map { |p| p[:name] }
1094
+ end
1095
+
1096
+ ###### Printers
836
1097
 
837
1098
  ### @return [Array] the id's of the printers handled by the policy
838
- def printer_ids; @printers.map{|p| p[:id]} ; end
1099
+ def printer_ids
1100
+ @printers.map { |p| p[:id] }
1101
+ end
839
1102
 
840
1103
  ### @return [Array] the names of the printers handled by the policy
841
- def printer_names; @printers.map{|p| p[:name]} ; end
1104
+ def printer_names
1105
+ @printers.map { |p| p[:name] }
1106
+ end
1107
+
1108
+ ###### SelfService
1109
+ ### Is this policy in self service?
1110
+ ###
1111
+ ### @return [Boolean] Is this policy in self service?
1112
+ ###
1113
+ def in_self_service?
1114
+ @in_self_service
1115
+ end
1116
+
1117
+ ### policies in self service aren't 'removable'
1118
+ ###
1119
+ ### @return [FalseClass]
1120
+ ###
1121
+ def user_removable?
1122
+ false
1123
+ end
1124
+ alias user_removable= user_removable?
1125
+
1126
+ ### Add this policy to Self Service
1127
+ ###
1128
+ ### @return [void]
1129
+ def add_to_self_service
1130
+ @need_to_update = (@in_self_service == false)
1131
+ @in_self_service = true
1132
+ end
1133
+
1134
+ ### Remove this policy from Self Service
1135
+ ###
1136
+ ### @return [void]
1137
+ def remove_from_self_service
1138
+ @need_to_update = (@in_self_service == true)
1139
+ @in_self_service = false
1140
+ end
1141
+
1142
+ ### Select or upload an image file to be the self service icon.
1143
+ ### The policy must already exist in the JSS to upload an image.
1144
+ ###
1145
+ ### NOTE: There is no way to verify the validity of an icon id, as they are not
1146
+ ### available via the API. Caveat Emptor.
1147
+ ###
1148
+ ### NOTE: When setting by id, {#update} or #{save} must be used to save the change.
1149
+ ###
1150
+ ### @param icon [String, Pathname, Integer] the path to the local image file, to upload
1151
+ ### or the id of a previously uploaded one.
1152
+ ###
1153
+ ### @return [void]
1154
+ ###
1155
+ def assign_icon(icon)
1156
+ if icon.is_a? Integer
1157
+ @self_service_icon = { id: icon }
1158
+ @need_to_update = true
1159
+ return
1160
+ end
1161
+ upload(:icon, icon)
1162
+ end
1163
+
1164
+ ###### Actions
842
1165
 
843
- ### @return [Boolean] is this policy available in SelfService?
844
- def self_service?; @self_service[:use_for_self_service] ; end
845
-
846
1166
  ### Try to execute this policy on this machine.
847
1167
  ###
848
- ### @param show_output[Boolean] should the stdout and stderr of the
1168
+ ### @param show_output[Boolean] should the stdout and stderr of the
849
1169
  ### 'jamf policy' command be sent to stdout in realtime?
850
1170
  ###
851
1171
  ### @return [Boolean, nil] The success of the 'jamf policy' command, or nil
852
1172
  ### if the policy couldn't be executed (out of scope, policy disabled, etc)
853
1173
  ###
854
- def run (show_output = false)
1174
+ def run(show_output = false)
855
1175
  return nil unless enabled?
856
- output = JSS::Client.run_jamf("policy", "-id #{id}", show_output)
1176
+ output = JSS::Client.run_jamf('policy', "-id #{id}", show_output)
857
1177
  return nil if output.include? 'No policies were found for the ID'
858
- return $?.exitstatus == 0 ? true : false
1178
+ $CHILD_STATUS.exitstatus.zero? ? true : false
859
1179
  end
860
-
861
- ### Aliases
1180
+
1181
+ ###### Aliases
1182
+
862
1183
  alias enabled? enabled
863
1184
  alias pkgs packages
864
1185
  alias command_to_run run_command
865
1186
  alias delete_path? delete_file?
866
1187
  alias execute run
867
-
868
- #####################################
1188
+ alias self_service? in_self_service?
1189
+
869
1190
  ### Private Instance Methods
870
1191
  #####################################
871
1192
  private
@@ -874,25 +1195,43 @@ module JSS
874
1195
  doc = REXML::Document.new APIConnection::XML_HEADER
875
1196
  obj = doc.add_element RSRC_OBJECT_KEY.to_s
876
1197
 
877
- general = obj.add_element "general"
1198
+ general = obj.add_element 'general'
878
1199
  general.add_element('name').text = @name
879
1200
  general.add_element('enabled').text = @enabled
880
1201
  general.add_element('frequency').text = @frequency
881
1202
  general.add_element('target_drive').text = @target_drive
882
1203
  general.add_element('offline').text = @offline
883
- general.add_element('category').add_element('name').text = @category
1204
+ general.add_element('category').add_element('name').text = @category if @category
884
1205
 
885
- JSS.hash_to_rexml_array(@trigger_events).each{|t| general << t}
1206
+ JSS.hash_to_rexml_array(@trigger_events).each { |t| general << t }
886
1207
 
887
1208
  obj << @scope.scope_xml
888
1209
 
889
- files_processes = obj.add_element "files_processes"
890
- JSS.hash_to_rexml_array(@files_processes).each{|f| files_processes << f}
1210
+ files_processes = obj.add_element 'files_processes'
1211
+ JSS.hash_to_rexml_array(@files_processes).each { |f| files_processes << f }
891
1212
 
892
- return doc.to_s
1213
+ pkg_conf = obj.add_element 'package_configuration'
1214
+ pkgs = pkg_conf.add_element 'packages'
1215
+ @packages.each do |p|
1216
+ pkg = pkgs.add_element 'package'
1217
+ pdeets = JSS.hash_to_rexml_array p
1218
+ pdeets.each { |d| pkg << d }
1219
+ end
1220
+
1221
+ scripts = obj.add_element 'scripts'
1222
+ @scripts.each do |s|
1223
+ script = scripts.add_element 'script'
1224
+ sdeets = JSS.hash_to_rexml_array s
1225
+ sdeets.each { |d| script << d }
1226
+ end
1227
+
1228
+ self_svc = self_service_xml
1229
+ self_svc.add_element('use_for_self_service').text = @in_self_service
1230
+ obj << self_svc
1231
+
1232
+ doc.to_s
893
1233
  end
894
1234
 
895
1235
  end # class policy
896
1236
 
897
1237
  end # module
898
-