ruby-jss 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +29 -22
  3. data/README.md +66 -86
  4. data/bin/jamfHelperBackgrounder +148 -0
  5. data/bin/netseg-update +0 -1
  6. data/lib/jss.rb +20 -9
  7. data/lib/jss/api_connection.rb +369 -295
  8. data/lib/jss/api_object.rb +651 -418
  9. data/lib/jss/api_object/account.rb +69 -77
  10. data/lib/jss/api_object/advanced_search.rb +201 -236
  11. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +42 -42
  12. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +33 -43
  13. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +33 -43
  14. data/lib/jss/api_object/building.rb +39 -52
  15. data/lib/jss/api_object/categorizable.rb +221 -0
  16. data/lib/jss/api_object/category.rb +81 -89
  17. data/lib/jss/api_object/computer.rb +486 -525
  18. data/lib/jss/api_object/computer_invitation.rb +73 -86
  19. data/lib/jss/api_object/criteriable.rb +6 -7
  20. data/lib/jss/api_object/ebook.rb +21 -0
  21. data/lib/jss/api_object/extendable.rb +6 -8
  22. data/lib/jss/api_object/group.rb +0 -3
  23. data/lib/jss/api_object/locatable.rb +19 -20
  24. data/lib/jss/api_object/mac_application.rb +21 -0
  25. data/lib/jss/api_object/mobile_device.rb +30 -21
  26. data/lib/jss/api_object/mobile_device_application.rb +447 -0
  27. data/lib/jss/api_object/mobile_device_configuration_profile.rb +21 -0
  28. data/lib/jss/api_object/osx_configuration_profile.rb +0 -3
  29. data/lib/jss/api_object/package.rb +21 -34
  30. data/lib/jss/api_object/peripheral.rb +16 -18
  31. data/lib/jss/api_object/policy.rb +5 -83
  32. data/lib/jss/api_object/purchasable.rb +11 -13
  33. data/lib/jss/api_object/scopable.rb +11 -12
  34. data/lib/jss/api_object/script.rb +3 -17
  35. data/lib/jss/api_object/self_servable.rb +419 -205
  36. data/lib/jss/api_object/self_servable/icon.rb +179 -0
  37. data/lib/jss/api_object/updatable.rb +35 -34
  38. data/lib/jss/api_object/uploadable.rb +72 -70
  39. data/lib/jss/api_object/user.rb +6 -7
  40. data/lib/jss/api_object/vppable.rb +117 -0
  41. data/lib/jss/client.rb +264 -225
  42. data/lib/jss/db_connection.rb +7 -5
  43. data/lib/jss/exceptions.rb +50 -42
  44. data/lib/jss/ruby_extensions.rb +8 -7
  45. data/lib/jss/ruby_extensions/object.rb +19 -0
  46. data/lib/jss/utility.rb +82 -40
  47. data/lib/jss/version.rb +1 -1
  48. metadata +37 -68
  49. data/bin/jss-webhook-server +0 -3
  50. data/lib/jss/webhooks.rb +0 -53
  51. data/lib/jss/webhooks/README.md +0 -269
  52. data/lib/jss/webhooks/configuration.rb +0 -213
  53. data/lib/jss/webhooks/data/sample_handlers/RestAPIOperation-executable +0 -91
  54. data/lib/jss/webhooks/data/sample_handlers/RestAPIOperation.rb +0 -45
  55. data/lib/jss/webhooks/data/sample_jsons/ComputerAdded.json +0 -27
  56. data/lib/jss/webhooks/data/sample_jsons/ComputerCheckIn.json +0 -27
  57. data/lib/jss/webhooks/data/sample_jsons/ComputerInventoryCompleted.json +0 -27
  58. data/lib/jss/webhooks/data/sample_jsons/ComputerPolicyFinished.json +0 -27
  59. data/lib/jss/webhooks/data/sample_jsons/ComputerPushCapabilityChanged.json +0 -27
  60. data/lib/jss/webhooks/data/sample_jsons/JSSShutdown.json +0 -14
  61. data/lib/jss/webhooks/data/sample_jsons/JSSStartup.json +0 -14
  62. data/lib/jss/webhooks/data/sample_jsons/MobileDeviceCheckIn.json +0 -26
  63. data/lib/jss/webhooks/data/sample_jsons/MobileDeviceCommandCompleted.json +0 -26
  64. data/lib/jss/webhooks/data/sample_jsons/MobileDeviceEnrolled.json +0 -26
  65. data/lib/jss/webhooks/data/sample_jsons/MobileDevicePushSent.json +0 -26
  66. data/lib/jss/webhooks/data/sample_jsons/MobileDeviceUnEnrolled.json +0 -26
  67. data/lib/jss/webhooks/data/sample_jsons/PatchSoftwareTitleUpdated.json +0 -14
  68. data/lib/jss/webhooks/data/sample_jsons/PushSent.json +0 -11
  69. data/lib/jss/webhooks/data/sample_jsons/RestAPIOperation.json +0 -15
  70. data/lib/jss/webhooks/data/sample_jsons/SCEPChallenge.json +0 -10
  71. data/lib/jss/webhooks/data/sample_jsons/SmartGroupComputerMembershipChange.json +0 -13
  72. data/lib/jss/webhooks/data/sample_jsons/SmartGroupMobileDeviceMembershipChange.json +0 -13
  73. data/lib/jss/webhooks/event.rb +0 -139
  74. data/lib/jss/webhooks/event/computer_added.rb +0 -38
  75. data/lib/jss/webhooks/event/computer_check_in.rb +0 -38
  76. data/lib/jss/webhooks/event/computer_inventory_completed.rb +0 -38
  77. data/lib/jss/webhooks/event/computer_policy_finished.rb +0 -38
  78. data/lib/jss/webhooks/event/computer_push_capability_changed.rb +0 -38
  79. data/lib/jss/webhooks/event/handlers.rb +0 -192
  80. data/lib/jss/webhooks/event/jss_shutdown.rb +0 -38
  81. data/lib/jss/webhooks/event/jss_startup.rb +0 -38
  82. data/lib/jss/webhooks/event/mobile_device_check_in.rb +0 -38
  83. data/lib/jss/webhooks/event/mobile_device_command_completed.rb +0 -38
  84. data/lib/jss/webhooks/event/mobile_device_enrolled.rb +0 -38
  85. data/lib/jss/webhooks/event/mobile_device_push_sent.rb +0 -38
  86. data/lib/jss/webhooks/event/mobile_device_unenrolled.rb +0 -38
  87. data/lib/jss/webhooks/event/patch_software_title_updated.rb +0 -38
  88. data/lib/jss/webhooks/event/push_sent.rb +0 -38
  89. data/lib/jss/webhooks/event/rest_api_operation.rb +0 -38
  90. data/lib/jss/webhooks/event/scep_challenge.rb +0 -38
  91. data/lib/jss/webhooks/event/smart_group_computer_membership_change.rb +0 -38
  92. data/lib/jss/webhooks/event/smart_group_mobile_device_membership_change.rb +0 -38
  93. data/lib/jss/webhooks/event/webhook.rb +0 -40
  94. data/lib/jss/webhooks/event_objects.rb +0 -112
  95. data/lib/jss/webhooks/event_objects/computer.rb +0 -49
  96. data/lib/jss/webhooks/event_objects/jss.rb +0 -36
  97. data/lib/jss/webhooks/event_objects/mobile_device.rb +0 -48
  98. data/lib/jss/webhooks/event_objects/patch_software_title_update.rb +0 -38
  99. data/lib/jss/webhooks/event_objects/push.rb +0 -33
  100. data/lib/jss/webhooks/event_objects/rest_api_operation.rb +0 -37
  101. data/lib/jss/webhooks/event_objects/scep_challenge.rb +0 -32
  102. data/lib/jss/webhooks/event_objects/smart_group.rb +0 -35
  103. data/lib/jss/webhooks/server_app.rb +0 -37
  104. data/lib/jss/webhooks/server_app/routes.rb +0 -27
  105. data/lib/jss/webhooks/server_app/routes/handle_webhook_event.rb +0 -39
  106. data/lib/jss/webhooks/server_app/routes/home.rb +0 -37
  107. data/lib/jss/webhooks/server_app/self_signed_cert.rb +0 -65
  108. data/lib/jss/webhooks/server_app/server.rb +0 -60
  109. data/lib/jss/webhooks/version.rb +0 -32
@@ -1,26 +1,26 @@
1
1
  ### Copyright 2017 Pixar
2
2
 
3
- ###
3
+ ###
4
4
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
5
5
  ### with the following modification; you may not use this file except in
6
6
  ### compliance with the Apache License and the following modification to it:
7
7
  ### Section 6. Trademarks. is deleted and replaced with:
8
- ###
8
+ ###
9
9
  ### 6. Trademarks. This License does not grant permission to use the trade
10
10
  ### names, trademarks, service marks, or product names of the Licensor
11
11
  ### and its affiliates, except as required to comply with Section 4(c) of
12
12
  ### the License and to reproduce the content of the NOTICE file.
13
- ###
13
+ ###
14
14
  ### You may obtain a copy of the Apache License at
15
- ###
15
+ ###
16
16
  ### http://www.apache.org/licenses/LICENSE-2.0
17
- ###
17
+ ###
18
18
  ### Unless required by applicable law or agreed to in writing, software
19
19
  ### distributed under the Apache License with the above modification is
20
20
  ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
21
  ### KIND, either express or implied. See the Apache License for the specific
22
22
  ### language governing permissions and limitations under the Apache License.
23
- ###
23
+ ###
24
24
  ###
25
25
 
26
26
  ###
@@ -50,7 +50,6 @@ module JSS
50
50
  ###
51
51
  ### Classes that mix in this module must:
52
52
  ### - Set a Constant SCOPE_TARGET_KEY that is either :computers or :mobile_devices
53
- ### - Call {#parse_scope} during initialization to make a {JSS::Scopable::Scope} instance for their @scope attribute.
54
53
  ### - Include the result of self.scope.scope_xml in their own rest_xml output if they are {Updatable} or {Creatable}
55
54
  ###
56
55
  module Scopable
@@ -112,25 +111,25 @@ module JSS
112
111
  @need_to_update = true if @in_jss
113
112
  end
114
113
 
115
-
114
+
116
115
  ###
117
116
  ### A wrapper around the update method, to try catching RestClient::Conflict
118
117
  ### 409 errors when we couldn't verify all ldap users/groups due to lack of ldap connections
119
- ###
118
+ ###
120
119
  def update
121
120
  begin
122
121
  super
123
-
122
+
124
123
  rescue RestClient::Conflict => conflict
125
124
  if self.scope.unable_to_verify_ldap_entries == true
126
125
  raise JSS::InvalidDataError, "Potentially non-existant LDAP user or group in new scope values."
127
126
  else
128
127
  raise conflict
129
128
  end
130
-
129
+
131
130
  end # begin
132
131
  end # update
133
-
132
+
134
133
  end # module Scopable
135
134
  end # module JSS
136
135
 
@@ -61,6 +61,7 @@ module JSS
61
61
 
62
62
  include JSS::Creatable
63
63
  include JSS::Updatable
64
+ include JSS::Categorizable
64
65
 
65
66
  ### Class Methods
66
67
  #####################################
@@ -127,7 +128,6 @@ module JSS
127
128
  def initialize(args = {})
128
129
  super
129
130
 
130
- @category = JSS::APIObject.get_name(@init_data[:category])
131
131
  @filename = @init_data[:filename] || @name
132
132
  @info = @init_data[:info]
133
133
  @notes = @init_data[:notes]
@@ -263,21 +263,6 @@ module JSS
263
263
  @need_to_update = true
264
264
  end # notes=
265
265
 
266
- ### Change the category
267
- ###
268
- ### @param new_val[String] the name of the new category, which must be in {JSS::Category.all_names}
269
- ###
270
- ### @return [void]
271
- ###
272
- def category=(new_val)
273
- return nil if new_val == @category
274
- new_val = nil if new_val == ''
275
- new_val ||= JSS::Category::DEFAULT_CATEGORY
276
- raise JSS::InvalidDataError, "Category #{new_val} is not known to the JSS" unless JSS::Category.all_names.include? new_val
277
- @need_to_update = true
278
- @category = new_val
279
- end # category=
280
-
281
266
  ### Replace all the script parameters at once.
282
267
  ###
283
268
  ### This will replace the entire set with the hash provided.
@@ -570,7 +555,7 @@ module JSS
570
555
  def rest_xml
571
556
  doc = REXML::Document.new
572
557
  scpt = doc.add_element 'script'
573
- scpt.add_element('category').text = @category
558
+
574
559
  scpt.add_element('filename').text = @filename
575
560
  scpt.add_element('id').text = @id
576
561
  scpt.add_element('info').text = @info
@@ -578,6 +563,7 @@ module JSS
578
563
  scpt.add_element('notes').text = @notes
579
564
  scpt.add_element('os_requirements').text = JSS.to_s_and_a(@os_requirements)[:stringform]
580
565
  scpt.add_element('priority').text = @priority
566
+ add_category_to_xml(doc)
581
567
 
582
568
  if @parameters.empty?
583
569
  scpt.add_element('parameters').text = nil
@@ -23,184 +23,197 @@
23
23
  ###
24
24
  ###
25
25
 
26
+ require 'jss/api_object/self_servable/icon'
27
+
26
28
  ###
27
29
  module JSS
28
30
 
29
- #####################################
30
- ### Module Variables
31
+ # Module Variables
31
32
  #####################################
32
33
 
33
- #####################################
34
- ### Module Methods
34
+ # Module Methods
35
35
  #####################################
36
36
 
37
- #####################################
38
- ### Sub-Modules
37
+ # Sub-Modules
39
38
  #####################################
40
39
 
41
- ### A mix-in module for handling Self Service data for objects in the JSS.
42
- ###
43
- ### The JSS objects that have Self Service data return it in a :self_service subset,
44
- ### which have somewhat similar data, i.e. a hash with at least these keys:
45
- ### - :self_service_description
46
- ### - :self_service_icon
47
- ### - :feature_on_main_page
48
- ### - :self_service_categories
49
- ###
50
- ### Config Profiles in self service have this key:
51
- ### - :security
52
- ###
53
- ### Additionally, items that apper in macOS Slf Svc have these keys:
54
- ### - :install_button_text
55
- ### - :force_users_to_view_description
56
- ###
57
- ### See the attribute definitions for details of these values and structures.
58
- ###
59
- ### Including this module in an {APIObject} subclass and calling {#parse_self_service} in the
60
- ### subclass's constructor will give it matching attributes with 'self_service_'
61
- ### appended if needed, e.g. {#self_service_feature_on_main_page}
62
- ###
63
- ###
64
- ### Classes including this module *must*:
65
- ###
66
- ### - Define the constant SELF_SERVICE_TARGET which contains either :macos or :ios
67
- ### - Define the constant SELF_SERVICE_PAYLOAD which contains one of :policy, :profile,
68
- ### :app, or :ebook
69
- ### - Call {#parse_self_service} in the subclass's constructor, after calling super
70
- ### - Define the method #in_self_service? which returns a Boolean indicating that the item is
71
- ### available in self service. Different API objects indicate this in different ways (and
72
- ### macOS app store apps don't provide it at all via the API,
73
- ### so self service can't be implemented fully)
74
- ### - Define the methods #add_to_self_service and #remove_from_self_service, which is handled
75
- ### differently for policies, apps/ebooks, and profiles
76
- ### - Define the method #user_removable? which returns Boolean indicating that the item
77
- ### can be removed by the user in SSvc. macOS profiles store this in the :user_removable
78
- ### key of the :general subset as a boolean, whereas iOS profiles store it in
79
- ### the :security hash of the :self_service data as one of 3 strings
80
- ### - Define the method #user_removable= which sets the appropriate values depending
81
- ### on the class. (see above)
82
- ### - Define a #set_icon_to method which takes the id of a previously uploaded
83
- ### icon, or a local path (String or Pathname) to an image file to use.
84
- ### - Include the result of {#self_service_xml} in their #rest_xml output
85
- ###
86
- ###
87
- ### Generating XML for PUT or POST:
88
- ###
89
- ### If the class including this module is creatable or updatable, calling {#self_service_xml}
90
- ### returns a REXML element representing the Self Service subset, to be included with the
91
- ### #rest_xml output of the subclass.
92
- ###
93
- ### Because some self-service-related data is located outside of the Self Service
94
- ### data subset (e.g. the deployment method for profiles is in the general subset),
95
- ### classes including this module *must* also account for that and add an appropriate
96
- ### XML element as needed.
97
- ###
40
+ # A mix-in module for handling Self Service data for objects in the JSS.
41
+ #
42
+ # The JSS objects that have Self Service data return it in a :self_service subset,
43
+ # which have somewhat similar data, i.e. a hash with at least these keys:
44
+ # - :self_service_description
45
+ # - :self_service_icon
46
+ # - :feature_on_main_page
47
+ # - :self_service_categories
48
+ #
49
+ # Config Profiles in self service have this key:
50
+ # - :security
51
+ #
52
+ # Additionally, items that apper in macOS Slf Svc have these keys:
53
+ # - :install_button_text
54
+ # - :force_users_to_view_description
55
+ #
56
+ # See the attribute definitions for details of these values and structures.
57
+ #
58
+ # Including this module in an {APIObject} subclass will give it matching
59
+ # attributes with 'self_service_' appended if needed,
60
+ # e.g. {#self_service_feature_on_main_page}
61
+ #
62
+ #
63
+ # Classes including this module *MUST*:
64
+ # - call {#add_self_service_xml()} in their #rest_xml method
65
+ #
66
+ # IMPORTANT: Since SelfServable also includes #{JSS::Updatable}, for uploading icons,
67
+ # see that module for its requirements.
68
+ #
69
+ #
98
70
  module SelfServable
99
71
 
100
- ### Constants
72
+ include Uploadable
73
+
74
+ # Constants
101
75
  #####################################
102
76
 
103
77
  SELF_SERVABLE = true
104
78
 
105
- IOS_PROFILE_REMOVAL_OPTIONS = ['Always', 'With Authorization', 'Never'].freeze
106
-
107
- ### Variables
79
+ PROFILE_REMOVAL_BY_USER = {
80
+ always: 'Always',
81
+ never: 'Never',
82
+ with_auth: 'With Authorization'
83
+ }.freeze
84
+
85
+ MAKE_AVAILABLE = 'Make Available in Self Service'.freeze
86
+ AUTO_INSTALL = 'Install Automatically'.freeze
87
+ AUTO_INSTALL_OR_PROMPT = 'Install Automatically/Prompt Users to Install'.freeze
88
+
89
+ DEFAULT_INSTALL_BUTTON_TEXT = 'Install'.freeze
90
+
91
+ SELF_SERVICE_CLASSES = {
92
+ JSS::Policy => {
93
+ in_self_service_data_path: [:self_service, :use_for_self_service],
94
+ in_self_service: true,
95
+ not_in_self_service: false,
96
+ targets: [:macos],
97
+ payload: :policy,
98
+ can_display_in_categories: true,
99
+ can_feature_in_categories: true
100
+ },
101
+ JSS::MacApplication => { # TODO: add the correct values when Jamf fixes this bug
102
+ in_self_service_data_path: nil, # [:general, :distribution_method],
103
+ in_self_service: nil, # MAKE_AVAILABLE,
104
+ not_in_self_service: nil, # AUTO_INSTALL_OR_PROMPT,
105
+ targets: [:macos],
106
+ payload: :app,
107
+ can_display_in_categories: true,
108
+ can_feature_in_categories: true
109
+ },
110
+ JSS::OSXConfigurationProfile => {
111
+ in_self_service_data_path: [:general, :distribution_method],
112
+ in_self_service: MAKE_AVAILABLE,
113
+ not_in_self_service: AUTO_INSTALL,
114
+ targets: [:macos],
115
+ payload: :profile,
116
+ can_display_in_categories: true,
117
+ can_feature_in_categories: true
118
+ },
119
+ JSS::EBook => {
120
+ in_self_service_data_path: [:general, :deployment_type],
121
+ in_self_service: MAKE_AVAILABLE,
122
+ not_in_self_service: AUTO_INSTALL_OR_PROMPT,
123
+ targets: [:macos, :ios],
124
+ payload: :app, # ebooks are handled the same way as apps, it seems,
125
+ can_display_in_categories: true,
126
+ can_feature_in_categories: true
127
+ },
128
+ JSS::MobileDeviceApplication => {
129
+ in_self_service_data_path: [:general, :deployment_type],
130
+ in_self_service: MAKE_AVAILABLE,
131
+ not_in_self_service: AUTO_INSTALL_OR_PROMPT,
132
+ targets: [:ios],
133
+ payload: :app,
134
+ can_display_in_categories: true,
135
+ can_feature_in_categories: false
136
+ },
137
+ JSS::MobileDeviceConfigurationProfile => {
138
+ in_self_service_data_path: [:general, :deployment_method],
139
+ in_self_service: MAKE_AVAILABLE,
140
+ not_in_self_service: AUTO_INSTALL,
141
+ targets: [:ios],
142
+ payload: :profile,
143
+ can_display_in_categories: false,
144
+ can_feature_in_categories: false
145
+ }
146
+ }.freeze
147
+
148
+ # Variables
108
149
  #####################################
109
150
 
110
- ### Attribtues
151
+ # Mixed-in Attributes
111
152
  #####################################
112
153
 
113
- ### @return [String] The verbage that appears in SelfSvc for this item
154
+ # @return [Boolean] Is this thing available in Self Service?
155
+ attr_reader :in_self_service
156
+ alias in_self_service? in_self_service
157
+
158
+ # @return [JSS::Icon, nil] The icon used in self-service
159
+ attr_reader :icon
160
+ alias self_service_icon icon
161
+
162
+ # @return [String] The verbage that appears in SelfSvc for this item
114
163
  attr_reader :self_service_description
115
164
 
116
- ### @return [Boolean] Should this item feature on the main page of SSvc?
165
+ # @return [Boolean] Should this item feature on the main page of SSvc?
166
+ # Only applicable to macOS targets
117
167
  attr_reader :self_service_feature_on_main_page
118
168
 
119
- ### @return [Array<Hash>] The categories in which this item should appear in SSvc
120
- ###
121
- ### Each Hash has these keys about the category
122
- ### - :id => [Integer] the JSS id of the category
123
- ### - :name => [String] the name of the category
124
- ###
125
- ### Most objects also include one or both of these keys:
126
- ### - :display_in => [Boolean] should the item be displayed in this category in SSvc? (OSX SSvc only)
127
- ### - :feature_in => [Boolean] should the item be featured in this category in SSVC? (OSX SSvc only)
128
- ###
129
- ### NOTE: as of Casper 9.61 there's a bug in the JSON output from the API, and only the last
130
- ### category is returned, if more than one are set.
131
- ###
169
+ # @return [Array<Hash>] The categories in which this item should appear in SSvc
170
+ #
171
+ # Each Hash has these keys about the category
172
+ # - :id => [Integer] the JSS id of the category
173
+ # - :name => [String] the name of the category
174
+ #
175
+ # Most objects also include one or both of these keys:
176
+ # - :display_in => [Boolean] should the item be displayed in this category in SSvc? (not MobDevConfProfiles)
177
+ # - :feature_in => [Boolean] should the item be featured in this category in SSVC? (macOS targets only)
178
+ #
132
179
  attr_reader :self_service_categories
133
180
 
134
- ### @return [Hash] The icon that appears in SelfSvc for this item
135
- ###
136
- ### The Hash contains these keys with info about the icon:
137
- ### - :uri => [String] the URI for retriving the icon
138
- ### - :id => [Integer] the JSS id number for the icon (not all SSvc items have this)
139
- ### - :data => [String] the icon image encoded as Base64 (not all SSvc items have this)
140
- ### - :filename => [String] The name of the image file uploaded to the JSS, if applicable
141
- ###
142
- attr_reader :self_service_icon
143
-
144
- ### @return [Hash] The security settings for profiles in SSvc
145
- ###
146
- ### The keys are
147
- ### - :removal_disallowed => [String] one of the items in PROFILE_REMOVAL_OPTIONS
148
- ### - :password => [String] if :removal_disallowed is "With Authorization", this contains the passwd (in plaintext)
149
- ### needed to remove the profile.
150
- ###
151
- ### NOTE that the key should be called :removal_allowed, since 'Never' means it can't be removed.
152
- ###
181
+ # Profiles in Self Service have an option to allow the user to remove them
182
+ # and for iOS profiles, if authentication is required to do so, and if so,
183
+ # the password needed for removal.
184
+ #
185
+ # This data is held in the :security Hash of the selfsvc data.
186
+ # The keys are:
187
+ # - :removal_disallowed, which should be "removal allowed"
188
+ # - :password => [String] if :removal_disallowed is "With Authorization",
189
+ # this contains the passwd (in plaintext) needed to remove the profile.
190
+ #
191
+ # NOTE that the key should be called :removal_allowed, since 'Never' means it can't be removed.
192
+ #
193
+ # These values are stored in the next two attributes.
194
+
195
+ # @return [Symbol] one of the keys in PROFILE_REMOVAL_BY_USER
153
196
  attr_reader :self_service_user_removable
154
197
 
155
- ### @return [String] The text label on the install button in SSvc (OSX SSvc only)
198
+ # @return [String] The password needed for removal, in plain text.
199
+ attr_reader :self_service_removal_password
200
+
201
+ # @return [String] The text label on the install button in SSvc (OSX SSvc only)
156
202
  attr_reader :self_service_install_button_text
157
203
 
158
- ### @return [Boolean] Should an extra window appear before the user can install the item? (OSX SSvc only)
204
+ # @return [Boolean] Should an extra window appear before the user can install the item? (OSX SSvc only)
159
205
  attr_reader :self_service_force_users_to_view_description
160
206
 
207
+ # Mixed-in Public Instance Methods
161
208
  #####################################
162
- ### Mixed-in Instance Methods
163
- #####################################
164
-
165
- ### Call this during initialization of
166
- ### objects that have a self_service subset
167
- ### and the self_service attributes will be populated
168
- ### (as primary attributes) from @init_data
169
- ###
170
- ### @return [void]
171
- ###
172
- def parse_self_service
173
- @init_data[:self_service] ||= {}
174
- @ss_data = @init_data[:self_service]
175
-
176
- @self_service_description = @ss_data[:self_service_description]
177
- @self_service_icon = @ss_data[:self_service_icon]
178
- @self_service_icon ||= {}
179
-
180
- @self_service_feature_on_main_page = @ss_data[:feature_on_main_page]
181
- @self_service_feature_on_main_page ||= false
182
-
183
- @self_service_categories = @ss_data[:self_service_categories]
184
- @self_service_categories ||= []
185
-
186
- # make this an empty hash if needed
187
- @self_service_security = @ss_data[:security]
188
- @self_service_security ||= {}
189
209
 
190
- @self_service_install_button_text = @ss_data[:install_button_text]
191
- @self_service_install_button_text ||= 'Install'
210
+ # Setters
211
+ #
192
212
 
193
- @self_service_force_users_to_view_description = @ss_data[:force_users_to_view_description]
194
- @self_service_force_users_to_view_description ||= false
195
- end # parse
196
-
197
- ### Setters
198
- ###
199
-
200
- ### @param new_val[String] the new discription
201
- ###
202
- ### @return [void]
203
- ###
213
+ # @param new_val[String] the new discription
214
+ #
215
+ # @return [void]
216
+ #
204
217
  def self_service_description=(new_val)
205
218
  new_val.strip!
206
219
  return if @self_service_description == new_val
@@ -208,57 +221,68 @@ module JSS
208
221
  @need_to_update = true
209
222
  end
210
223
 
211
- ### @param new_val[String] the new install button text
212
- ###
213
- ### @return [void]
214
- ###
224
+ # @param new_val[String] the new install button text
225
+ #
226
+ # @return [void]
227
+ #
215
228
  def self_service_install_button_text=(new_val)
216
229
  return nil if @self_service_install_button_text == new_val
217
- raise JSS::InvalidDataError, 'Only OS X Self Service Items can have custom button text' unless self.class::SELF_SERVICE_TARGET == :macos
230
+ raise JSS::InvalidDataError, 'Only OS X Self Service Items can have custom button text' unless self_service_targets.include? :macos
218
231
  @self_service_install_button_text = new_val.strip
219
232
  @need_to_update = true
220
233
  end
221
234
 
222
- ### @param new_val[Boolean] should this appear on the main SelfSvc page?
223
- ###
224
- ### @return [void]
225
- ###
235
+ # @param new_val[Boolean] should this appear on the main SelfSvc page?
236
+ #
237
+ # @return [void]
238
+ #
226
239
  def self_service_feature_on_main_page=(new_val)
227
240
  return nil if @self_service_feature_on_main_page == new_val
228
- raise JSS::InvalidDataError, 'New value must be true or false' unless JSS::TRUE_FALSE.include? new_val
241
+ return nil unless @self_service_data_config[:can_feature_in_categories]
242
+ raise JSS::InvalidDataError, 'New value must be true or false' unless new_val.jss_boolean?
229
243
  @self_service_feature_on_main_page = new_val
230
244
  @need_to_update = true
231
245
  end
232
246
 
233
- ### @param new_val[Boolean] should this appear on the main SelfSvc page?
234
- ###
235
- ### @return [void]
236
- ###
247
+ # @param new_val[Boolean] Should the description be shown to users in a new
248
+ # window before executing the payload?
249
+ #
250
+ # @return [void]
251
+ #
237
252
  def self_service_force_users_to_view_description=(new_val)
238
253
  return nil if @self_service_force_users_to_view_description == new_val
239
- raise JSS::InvalidDataError, 'Only OS X Self Service Items can force users to view description' unless self.class::SELF_SERVICE_TARGET == :macos
240
- raise JSS::InvalidDataError, 'New value must be true or false' unless JSS::TRUE_FALSE.include? new_val
254
+ raise JSS::InvalidDataError, 'Only OS X Self Service Items can force users to view description' unless self_service_targets.include? :macos
255
+ raise JSS::InvalidDataError, 'New value must be true or false' unless new_val.jss_boolean?
241
256
  @self_service_force_users_to_view_description = new_val
242
257
  @need_to_update = true
243
258
  end
244
259
 
245
- ### Add or change one of the categories for this item in SSvc.
246
- ###
247
- ### @param new_cat[String] the name of a category for this item in SelfSvc
248
- ###
249
- ### @param display_in[Boolean] should this item appear in the SelfSvc page for the new category?
250
- ###
251
- ### @param feature_in[Boolean] should this item be featured in the SelfSvc page for the new category?
252
- ###
253
- ### @return [void]
254
- ###
260
+ # Add or change one of the categories for this item in self service
261
+ #
262
+ # @param new_cat[String, Integer] the name or id of a category where this
263
+ # object should appear in SelfSvc
264
+ #
265
+ # @param display_in[Boolean] should this item appear in the SelfSvc page for
266
+ # the category? Only meaningful in applicable classes
267
+ #
268
+ # @param feature_in[Boolean] should this item be featured in the SelfSvc page
269
+ # for the category? Only meaningful in applicable classes.
270
+ # NOTE: this will always be false if display_in is false.
271
+ #
272
+ # @return [void]
273
+ #
255
274
  def add_self_service_category(new_cat, display_in: true, feature_in: false)
256
- new_cat.strip!
275
+ new_cat = JSS::Category.map_all_ids_to(:name)[new_cat] if new_cat.is_a? Integer
276
+ feature_in = false if display_in == false
257
277
  raise JSS::NoSuchItemError, "No category '#{new_cat}' in the JSS" unless JSS::Category.all_names(:refresh).include? new_cat
258
- raise JSS::InvalidDataError, 'display_in must be true or false' unless JSS::TRUE_FALSE.include? display_in
259
- raise JSS::InvalidDataError, 'feature_in must be true or false' unless JSS::TRUE_FALSE.include? feature_in
260
278
 
261
- new_data = { name: new_cat, display_in: display_in, feature_in: feature_in }
279
+ raise JSS::InvalidDataError, 'display_in must be true or false' unless display_in.jss_boolean?
280
+
281
+ raise JSS::InvalidDataError, 'feature_in must be true or false' unless feature_in.jss_boolean?
282
+
283
+ new_data = { name: new_cat }
284
+ new_data[:display_in] = display_in if @self_service_data_config[:can_display_in_categories]
285
+ new_data[:feature_in] = feature_in if @self_service_data_config[:can_feature_in_categories]
262
286
 
263
287
  # see if this category is already among our categories.
264
288
  idx = @self_service_categories.index { |c| c[:name] == new_cat }
@@ -271,57 +295,247 @@ module JSS
271
295
 
272
296
  @need_to_update = true
273
297
  end
274
-
275
- ### Remove a category from those for this item in SSvc
276
- ###
277
- ### @param cat [String] the name of the category to remove
278
- ###
279
- ### @return [void]
280
- ###
298
+ alias set_self_service_category add_self_service_category
299
+
300
+ # Remove a category from those for this item in SSvc
301
+ #
302
+ # @param cat [String, Integer] the name or id of the category to remove
303
+ #
304
+ # @return [void]
305
+ #
281
306
  def remove_self_service_category(cat)
282
- @self_service_categories.reject! { |c| c[:name] == cat }
307
+ @self_service_categories.reject! { |c| c[:name] == cat || c[:id] == cat }
308
+ @need_to_update = true
309
+ end
310
+
311
+ # Set the value for user-removability of profiles, optionally
312
+ # providing a password for removal, on iOS targets.
313
+ #
314
+ # @param new_val[Symbol] One of the keys of PROFILE_REMOVAL_BY_USER,
315
+ # :always, :never, or :with_auth
316
+ #
317
+ # @param pw[String] A new password to use if removable :with_auth
318
+ #
319
+ # @return [void]
320
+ #
321
+ def self_service_user_removable=(new_val, pw = @self_service_removal_password)
322
+ return nil if new_val == @self_service_user_removable && pw == @self_service_removal_password
323
+ validate_user_removable new_val
324
+
325
+ @self_service_user_removable = new_val
326
+ @self_service_removal_password = pw
327
+ @need_to_update = true
328
+ end
329
+
330
+ # Set a new Self Service icon for this object.
331
+ #
332
+ # Since JSS::Icon objects are read-only,
333
+ # the icon can only be changed by supplying the id number
334
+ # of an icon already existing in the JSS, or a path to
335
+ # a local file, which will be uploaded to the JSS and added
336
+ # to this instance. Uploads
337
+ # take effect immediately, but if an integer is supplied, the change
338
+ # must be sent to the JSS via {#update} or {#create}
339
+ #
340
+ # @param new_icon[Integer, String, Pathname] The id or path to the new icon.
341
+ #
342
+ # @return [false, Integer, Pathname] false means no change was made.
343
+ #
344
+ def icon=(new_icon)
345
+ if new_icon.is_a? Integer
346
+ return if new_icon == @icon.id
347
+ validate_icon new_icon
348
+ @new_icon_id = new_icon
349
+ @need_to_update = true
350
+ else
351
+ unless uploadable? && self.class::UPLOAD_TYPES.keys.include?(:icon)
352
+ raise JSS::UnsupportedError, "Class #{self.class} does not support icon uploads."
353
+ end
354
+ new_icon = Pathname.new new_icon
355
+ upload(:icon, new_icon)
356
+ refresh_icon
357
+ end # new_icon.is_a? Integer
358
+ new_icon
359
+ end # icon =
360
+ alias self_service_icon= icon=
361
+ alias assign_icon icon=
362
+
363
+ # Add this object to self service if not already there.
364
+ #
365
+ # @return [void]
366
+ #
367
+ def add_to_self_service
368
+ return nil unless @self_service_data_config[:in_self_service_data_path]
369
+ return nil if in_self_service?
370
+ @in_self_service = true
283
371
  @need_to_update = true
284
372
  end
285
373
 
286
- ### @api private
287
- ###
288
- ### Return a REXML <location> element to be
289
- ### included in the rest_xml of
290
- ### objects that have a Location subset
291
- ###
292
- ### @return [REXML::Element]
293
- ###
294
- def self_service_xml
295
- ssvc = REXML::Element.new('self_service')
374
+ # Remove this object from self service if it's there.
375
+ #
376
+ # @return [void]
377
+ #
378
+ def remove_from_self_service
379
+ return nil unless @self_service_data_config[:in_self_service_data_path]
380
+ return nil unless in_self_service?
381
+ @in_self_service = false
382
+ @need_to_update = true
383
+ end
384
+
385
+ # Can this thing be removed by the user?
386
+ #
387
+ # @return [Boolean, nil] nil means 'not applicable'
388
+ #
389
+ def user_removable?
390
+ return nil unless self_service_payload == :profile
391
+ @self_service_user_removable != :never
392
+ end
393
+
394
+ # What devices types can get this thing in Self Service
395
+ #
396
+ # @return [Array<Symbol>] An array of :macos, :ios, or both.
397
+ #
398
+ def self_service_targets
399
+ @self_service_data_config[:targets]
400
+ end
401
+
402
+ # What does this object deploy to the device
403
+ # via self service?
404
+ #
405
+ # @return [Symbol] :profile, :app, or :policy
406
+ #
407
+ def self_service_payload
408
+ @self_service_data_config[:payload]
409
+ end
410
+
411
+ # Mixed-in Private Instance Methods
412
+ #####################################
413
+ private
414
+
415
+ # Call this during initialization of
416
+ # objects that have a self_service subset
417
+ # and the self_service attributes will be populated
418
+ # (as primary attributes) from @init_data
419
+ #
420
+ # @return [void]
421
+ #
422
+ def parse_self_service
423
+ ss_data = @init_data[:self_service]
424
+ ss_data ||= {}
425
+ @self_service_data_config = SELF_SERVICE_CLASSES[self.class]
426
+
427
+ @in_self_service = in_self_service_at_init?
428
+
429
+ if ss_data[:security]
430
+ removable_value = ss_data[:security][:removal_disallowed]
431
+ @self_service_user_removable = PROFILE_REMOVAL_BY_USER.invert[removable_value]
432
+ @self_service_removal_password = ss_data[:security][:password]
433
+ end
434
+
435
+ @self_service_description = ss_data[:self_service_description]
436
+
437
+ @icon = JSS::Icon.new(ss_data[:self_service_icon]) if ss_data[:self_service_icon]
438
+
439
+ @self_service_feature_on_main_page = ss_data[:feature_on_main_page]
440
+ @self_service_feature_on_main_page ||= false
441
+
442
+ @self_service_categories = ss_data[:self_service_categories]
443
+ @self_service_categories ||= []
444
+
445
+ @self_service_install_button_text = ss_data[:install_button_text]
446
+ @self_service_install_button_text ||= DEFAULT_INSTALL_BUTTON_TEXT
447
+
448
+ @self_service_force_users_to_view_description = ss_data[:force_users_to_view_description]
449
+ @self_service_force_users_to_view_description ||= false
450
+ end # parse
451
+
452
+ # Figure out if this object is in Self Service, from the API
453
+ # initialization data.
454
+ # Alas, how to do it is far from consistent
455
+ #
456
+ # @return [Boolean]
457
+ #
458
+ def in_self_service_at_init?
459
+ return nil unless @self_service_data_config[:in_self_service_data_path]
460
+ subsection, key = @self_service_data_config[:in_self_service_data_path]
461
+ @init_data[subsection][key] == @self_service_data_config[:in_self_service]
462
+ end
463
+
464
+ def validate_user_removable=(new_val)
465
+ raise JSS::UnsupportedError, 'User removal settings not applicable to this class' unless self_service_payload == :profile
466
+
467
+ raise JSS::UnsupportedError, 'Removal :with_auth not applicable to this class' if new_val == :with_auth && !self_service_targets.include?(:ios)
468
+
469
+ raise JSS::InvalidDataError, "Value must be one of: :#{PROFILE_REMOVAL_BY_USER.keys.join(', :')}" unless PROFILE_REMOVAL_BY_USER.keys.include? new_val
470
+ end
471
+
472
+ def validate_icon(id)
473
+ if JSS::DB_CNX.connected?
474
+ raise JSS::NoSuchItemError, "No icon with id #{new_icon}" unless JSS::Icon.all_ids.include? id
475
+ end
476
+ end
477
+ # Re-read the icon data for this object from the API
478
+ # Generally done after uploading a new icon via {#icon=}
479
+ #
480
+ # @return [void]
481
+ #
482
+ def refresh_icon
483
+ return nil unless @in_jss
484
+ fresh_data = JSS::API.get_rsrc(@rest_rsrc)[self.class::RSRC_OBJECT_KEY]
485
+ icon_data = fresh_data[:self_service][:self_service_icon]
486
+ @icon = JSS::Icon.new icon_data
487
+ end # refresh icon
488
+
489
+ # Add a REXML <self_service> element to the root of the provided REXML::Document
490
+ #
491
+ # @param xdoc[REXML::Document] The XML Document to which we're adding a Self
492
+ # Service subsection
493
+ #
494
+ # @return [void]
495
+ #
496
+ def add_self_service_xml(xdoc)
497
+ doc_root = xdoc.root
498
+ ssvc = doc_root.add_element 'self_service'
296
499
 
297
500
  ssvc.add_element('self_service_description').text = @self_service_description
298
501
  ssvc.add_element('feature_on_main_page').text = @self_service_feature_on_main_page
299
502
 
503
+ if @new_icon_id
504
+ icon = ssvc.add_element('self_service_icon')
505
+ icon.add_element('id').text = @new_icon_id
506
+ end
507
+
300
508
  cats = ssvc.add_element('self_service_categories')
301
509
  @self_service_categories.each do |cat|
302
510
  catelem = cats.add_element('category')
303
511
  catelem.add_element('name').text = cat[:name]
304
- catelem.add_element('display_in').text = cat[:display_in] if cat.keys.include? :display_in
305
- catelem.add_element('feature_in').text = cat[:feature_in] if cat.keys.include? :feature_in
512
+ catelem.add_element('display_in').text = cat[:display_in] if @self_service_data_config[:can_display_in_categories]
513
+ catelem.add_element('feature_in').text = cat[:feature_in] if @self_service_data_config[:can_feature_in_categories]
306
514
  end
307
515
 
308
- icon = ssvc.add_element('self_service_icon')
309
- @self_service_icon.each { |key, val| icon.add_element(key.to_s).text = val }
516
+ if self_service_targets.include? :macos
517
+ ssvc.add_element('install_button_text').text = @self_service_install_button_text
518
+ ssvc.add_element('force_users_to_view_description').text = @self_service_force_users_to_view_description
519
+ end
310
520
 
311
- unless @self_service_security.empty?
521
+ if self_service_payload == :profile
312
522
  sec = ssvc.add_element('security')
313
- sec.add_element('removal_disallowed').text = @self_service_security[:removal_disallowed] if @self_service_security[:removal_disallowed]
314
- sec.add_element('password').text = @self_service_security[:password] if @self_service_security[:password]
523
+ sec.add_element('removal_disallowed').text = PROFILE_REMOVAL_BY_USER[@self_service_user_removable]
524
+ sec.add_element('password').text = @self_service_removal_password if @self_service_removal_password
315
525
  end
316
526
 
317
- ssvc.add_element('install_button_text').text = @self_service_install_button_text if @self_service_install_button_text
318
- ssvc.add_element('force_users_to_view_description').text = @self_service_force_users_to_view_description \
319
- unless @self_service_force_users_to_view_description.nil?
527
+ return unless @self_service_data_config[:in_self_service_data_path]
320
528
 
321
- ssvc
322
- end
529
+ in_ss_section, in_ss_elem = @self_service_data_config[:in_self_service_data_path]
530
+
531
+ in_ss_value = @in_self_service ? @self_service_data_config[:in_self_service] : @self_service_data_config[:not_in_self_service]
532
+
533
+ in_ss_section_xml = doc_root.elements[in_ss_section.to_s]
534
+ in_ss_section_xml ||= doc_root.add_element(in_ss_section.to_s)
535
+ in_ss_section_xml.add_element(in_ss_elem.to_s).text = in_ss_value.to_s
536
+ end # add_self_service_xml
323
537
 
324
- ### aliases
538
+ # aliases
325
539
  alias change_self_service_category add_self_service_category
326
540
 
327
541
  end # module SelfServable