Module: D3::Admin::Edit

Extended by:
Edit
Included in:
Edit
Defined in:
lib/d3/admin/edit.rb

Constant Summary collapse

EDITING_OPTIONS =

These are all the options that can be edited for an existing d3 package. This also defines the order they’re presented when editing via walkthru.

This is defined as an array, separate from the keys of PKG_ATTRIBUTE_CONFIG

%w{
  version
  revision
  package_name
  filename
  category
  oses
  cpu_type
  reboot
  removable
  remove_first
  prohibiting_processes
  auto_groups
  excluded_groups
  pre_install
  post_install
  pre_remove
  post_remove
  expiration
  expiration_paths
  description
}.map{|i| i.to_sym}
NONE =

This is how nils and empty strings are displayed to the user

"none"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.check_for_new_group_overlaps(pkg, changes_to_make) ⇒ void

This method returns an undefined value.

Before making edits, confirm that the possibly new auto or excluded groups don’t overlap with each other.

Raises an exception if there are overlaps

Parameters:

  • pkg (D3::Package)

    the package we’re editing

  • changes_to_make (Hash)

    the changes we want to make



263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/d3/admin/edit.rb', line 263

def check_for_new_group_overlaps (pkg, changes_to_make)
  new_auto_gs = changes_to_make[:auto_groups]
  new_excl_gs = changes_to_make[:excluded_groups]
  bad_groups = []
  if new_excl_gs and new_auto_gs
    bad_groups = new_excl_gs & new_auto_gs
  elsif new_excl_gs
    bad_groups = new_excl_gs & pkg.auto_groups
  elsif new_auto_gs
    bad_groups = new_auto_gs & pkg.excluded_groups
  end
  raise "Auto and Excluded groups can't overlap!" unless bad_groups.empty?
  true
end

.check_new_edition(pkg, changes_to_make) ⇒ Hash

Before making edits, check the possibly new edition in two ways: 1) that it doesn’t conflict with another edition in d3 2) if the original package name contained the original edition

and the edition has changed, change the package name to match.

Raises an exception if there are edition conflicts

Parameters:

  • pkg (D3::Package)

    the package we’re editing

  • changes_to_make (Hash)

    the changes we want to make

Returns:

  • (Hash)

    changes_to_make with a possibly new :name



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/d3/admin/edit.rb', line 231

def check_new_edition (pkg, changes_to_make)
  new_vers = changes_to_make[:version]
  new_rev = changes_to_make[:revision]
  if new_vers or new_rev
    potential_edition = "#{pkg.basename}-#{new_vers ? new_vers : pkg.version}-#{new_rev ? new_rev : pkg.revision}"
    unless  pkg.edition == potential_edition
      # edition conflict?
      if  D3::Package.all_editions.include? potential_edition
        raise JSS::AlreadyExistsError, "Can't change version or revision as requested: edition conflict with #{potential_edition}"
      end

      # name syncing?
      if pkg.name.include? pkg.edition
        changes_to_make[:package_name] = pkg.name.sub(pkg.edition, potential_edition ) unless changes_to_make[:package_name]
      end
    end # unless
  end # if new_vers or new_rev

  return changes_to_make
end

.initial_editing_walkthru_state(pkg) ⇒ Hash

A hash of hashes holding the state of the various options of a pkg that can be edited during a walkthru.

For each editable option it holds:

  • the original value of the option from the pkg

  • the textual-display version of that value, as created by the matching :display_conversion proc in D3::Admin::EDITING_OPTION_INFO

  • The the new value when the user makes a change.

Parameters:

Returns:

  • (Hash)

    the walkthru-editing values for the pkg



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/d3/admin/edit.rb', line 139

def initial_editing_walkthru_state (pkg)
  editing_walkthru_state = {}
  EDITING_OPTIONS.each do |o|
    original_value = pkg.send(o)
    converter = D3::Admin::OPTIONS[o][:display_conversion]
    editing_walkthru_state[o] = {
      :original_value => original_value,
      :original_value_display => converter ? converter.call(original_value) : original_value,
      :new_value => original_value
    } # end hash
    # set orig value displays that are empty to 'none'
    editing_walkthru_state[o][:original_value_display] = NONE if editing_walkthru_state[o][:original_value_display].to_s.empty?
  end # EDITING_OPTIONS.each do |o|
  return editing_walkthru_state
end

.loop_thru_editing_walkthru(pkg) ⇒ Hash

Continuously loop through displaying the editing menu, and getting new values, until the user types ‘x’.

Parameters:

Returns:

  • (Hash)

    A hash of changes to make to the pkg. Keys are the option symbols from EDITING_OPTIONS, values are new values



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/d3/admin/edit.rb', line 71

def loop_thru_editing_walkthru (pkg)

  editing_walkthru_state = initial_editing_walkthru_state(pkg)

  walkthru_menu_header = <<-ENDMENU
------------------------------------
Editing #{pkg.status} d3 package '#{pkg.edition}'
JSS Package id: #{pkg.id}
JSS Package name: #{pkg.package_name}
Installer filename: #{pkg.filename}
------------------------------------
Current Settings => New Settings
  ENDMENU

  choice = nil

  # loop until the user types an x
  while choice != "x"

    choice = D3::Admin::Interactive.get_menu_choice( walkthru_menu_header, walkthru_menu_lines(editing_walkthru_state) )

    break if choice == 'x'

    # the number they chose becomes an option key like :reboot
    chosen_opt = EDITING_OPTIONS[choice]

    # Here's the definition of the option from the OPTIONS hash
    opt_def = D3::Admin::OPTIONS[chosen_opt]

    # Here the value we're actually editing
    orig_opt_value = editing_walkthru_state[chosen_opt][:original_value]
    orig_opt_value ||= opt_def[:default]

    # prompt for a new value and put it in place
    editing_walkthru_state[chosen_opt][:new_value] = D3::Admin::Interactive.get_value( chosen_opt, orig_opt_value )


  end # while choice != x

  # extract just the changes to make
  changes_to_make = {}
  editing_walkthru_state.each do |opt, data|
    comparer = D3::Admin::OPTIONS[opt][:compare]
    if comparer
      next if (comparer.call data[:original_value], data[:new_value])
    else
      next if (data[:original_value].to_s == data[:new_value].to_s)
    end
    changes_to_make[opt] = data[:new_value]
  end # editing_walkthru_state.each do |opt, data|

  return changes_to_make

end

.process_edits(pkg, changes_to_make) ⇒ void

This method returns an undefined value.

Make the changes that have been requested with an edit

Parameters:

  • pkg (D3::Package)

    the package we’re editing

  • changes_to_make (Hash)

    the changes we want to make



286
287
288
289
290
291
292
293
# File 'lib/d3/admin/edit.rb', line 286

def process_edits (pkg, changes_to_make)
  changes_to_make.each do |opt, new_val|
    setter = (opt.to_s + "=").to_sym
    pkg.send setter, new_val
  end
  pkg.save
  pkg.update_master_filename D3::Admin::Auth.rw_credentials(:dist)[:password] if changes_to_make[:filename]
end

.validate_cli_edits(cli_options) ⇒ Hash

Validate the desired edits from the CLI options

Parameters:

  • cli_options (OpenStruct)

    the options from the CLI

Returns:

  • (Hash)

    A hash of changes to make to the pkg. Keys are the option symbols from EDITING_OPTIONS, values are new values



203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/d3/admin/edit.rb', line 203

def validate_cli_edits (cli_options)
  changes_to_make = {}
  EDITING_OPTIONS.each do |opt|
    if cli_options[opt]
      opt_check = D3::Admin::OPTIONS[opt][:validate]
      if opt_check
        changes_to_make[opt] = D3::Admin::Validate.send(opt_check, cli_options[opt])
      else
        changes_to_make[opt] = cli_options[opt]
      end
    end # if @options[opt]
  end #.each do |opt|
  changes_to_make
end

.walkthru_menu_lines(editing_walkthru_state) ⇒ Array<String>

Regenerate the walkthru menu lines

Parameters:

  • editing_walkthru_state (Hash)

    the current state of the values being edited

Returns:

  • (Array<String>)

    the lines of the walkthru menu



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/d3/admin/edit.rb', line 161

def walkthru_menu_lines (editing_walkthru_state)

  display_lines = []
  EDITING_OPTIONS.each do |opt|
    # opt is the option symbol, like :reboot
    opt_def = D3::Admin::OPTIONS[opt]
    label = opt_def[:label]
    converter = opt_def[:display_conversion]

    # did the thing change?
    # compare the old and new either with .to_s and ==
    # or with the :compare proc defined in EDITING_OPTION_INFO
    if opt_def[:compare]
       option_didnt_change = (opt_def[:compare].call editing_walkthru_state[opt][:original_value], editing_walkthru_state[opt][:new_value])
    else
       option_didnt_change = (editing_walkthru_state[opt][:original_value].to_s ==  editing_walkthru_state[opt][:new_value].to_s)
    end

    # no change, so just display the orig value
    if option_didnt_change
      val_to_display = editing_walkthru_state[opt][:original_value_display]

    # But if the new val is different, convert it if needed, then show it as "orig => new"
    else
      new_value_display = converter ? converter.call(editing_walkthru_state[opt][:new_value]) : editing_walkthru_state[opt][:new_value]
      new_value_display = NONE if new_value_display.to_s.empty?
      val_to_display = "#{editing_walkthru_state[opt][:original_value_display]} => #{new_value_display}"
    end

    # make the line and add it to the array of lines
    display_lines << "#{label}: #{val_to_display}"
  end
  return display_lines
end

Instance Method Details

#check_for_new_group_overlaps(pkg, changes_to_make) ⇒ void

This method returns an undefined value.

Before making edits, confirm that the possibly new auto or excluded groups don’t overlap with each other.

Raises an exception if there are overlaps

Parameters:

  • pkg (D3::Package)

    the package we’re editing

  • changes_to_make (Hash)

    the changes we want to make



263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/d3/admin/edit.rb', line 263

def check_for_new_group_overlaps (pkg, changes_to_make)
  new_auto_gs = changes_to_make[:auto_groups]
  new_excl_gs = changes_to_make[:excluded_groups]
  bad_groups = []
  if new_excl_gs and new_auto_gs
    bad_groups = new_excl_gs & new_auto_gs
  elsif new_excl_gs
    bad_groups = new_excl_gs & pkg.auto_groups
  elsif new_auto_gs
    bad_groups = new_auto_gs & pkg.excluded_groups
  end
  raise "Auto and Excluded groups can't overlap!" unless bad_groups.empty?
  true
end

#check_new_edition(pkg, changes_to_make) ⇒ Hash

Before making edits, check the possibly new edition in two ways: 1) that it doesn’t conflict with another edition in d3 2) if the original package name contained the original edition

and the edition has changed, change the package name to match.

Raises an exception if there are edition conflicts

Parameters:

  • pkg (D3::Package)

    the package we’re editing

  • changes_to_make (Hash)

    the changes we want to make

Returns:

  • (Hash)

    changes_to_make with a possibly new :name



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/d3/admin/edit.rb', line 231

def check_new_edition (pkg, changes_to_make)
  new_vers = changes_to_make[:version]
  new_rev = changes_to_make[:revision]
  if new_vers or new_rev
    potential_edition = "#{pkg.basename}-#{new_vers ? new_vers : pkg.version}-#{new_rev ? new_rev : pkg.revision}"
    unless  pkg.edition == potential_edition
      # edition conflict?
      if  D3::Package.all_editions.include? potential_edition
        raise JSS::AlreadyExistsError, "Can't change version or revision as requested: edition conflict with #{potential_edition}"
      end

      # name syncing?
      if pkg.name.include? pkg.edition
        changes_to_make[:package_name] = pkg.name.sub(pkg.edition, potential_edition ) unless changes_to_make[:package_name]
      end
    end # unless
  end # if new_vers or new_rev

  return changes_to_make
end

#initial_editing_walkthru_state(pkg) ⇒ Hash

A hash of hashes holding the state of the various options of a pkg that can be edited during a walkthru.

For each editable option it holds:

  • the original value of the option from the pkg

  • the textual-display version of that value, as created by the matching :display_conversion proc in D3::Admin::EDITING_OPTION_INFO

  • The the new value when the user makes a change.

Parameters:

Returns:

  • (Hash)

    the walkthru-editing values for the pkg



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/d3/admin/edit.rb', line 139

def initial_editing_walkthru_state (pkg)
  editing_walkthru_state = {}
  EDITING_OPTIONS.each do |o|
    original_value = pkg.send(o)
    converter = D3::Admin::OPTIONS[o][:display_conversion]
    editing_walkthru_state[o] = {
      :original_value => original_value,
      :original_value_display => converter ? converter.call(original_value) : original_value,
      :new_value => original_value
    } # end hash
    # set orig value displays that are empty to 'none'
    editing_walkthru_state[o][:original_value_display] = NONE if editing_walkthru_state[o][:original_value_display].to_s.empty?
  end # EDITING_OPTIONS.each do |o|
  return editing_walkthru_state
end

#loop_thru_editing_walkthru(pkg) ⇒ Hash

Continuously loop through displaying the editing menu, and getting new values, until the user types ‘x’.

Parameters:

Returns:

  • (Hash)

    A hash of changes to make to the pkg. Keys are the option symbols from EDITING_OPTIONS, values are new values



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/d3/admin/edit.rb', line 71

def loop_thru_editing_walkthru (pkg)

  editing_walkthru_state = initial_editing_walkthru_state(pkg)

  walkthru_menu_header = <<-ENDMENU
------------------------------------
Editing #{pkg.status} d3 package '#{pkg.edition}'
JSS Package id: #{pkg.id}
JSS Package name: #{pkg.package_name}
Installer filename: #{pkg.filename}
------------------------------------
Current Settings => New Settings
  ENDMENU

  choice = nil

  # loop until the user types an x
  while choice != "x"

    choice = D3::Admin::Interactive.get_menu_choice( walkthru_menu_header, walkthru_menu_lines(editing_walkthru_state) )

    break if choice == 'x'

    # the number they chose becomes an option key like :reboot
    chosen_opt = EDITING_OPTIONS[choice]

    # Here's the definition of the option from the OPTIONS hash
    opt_def = D3::Admin::OPTIONS[chosen_opt]

    # Here the value we're actually editing
    orig_opt_value = editing_walkthru_state[chosen_opt][:original_value]
    orig_opt_value ||= opt_def[:default]

    # prompt for a new value and put it in place
    editing_walkthru_state[chosen_opt][:new_value] = D3::Admin::Interactive.get_value( chosen_opt, orig_opt_value )


  end # while choice != x

  # extract just the changes to make
  changes_to_make = {}
  editing_walkthru_state.each do |opt, data|
    comparer = D3::Admin::OPTIONS[opt][:compare]
    if comparer
      next if (comparer.call data[:original_value], data[:new_value])
    else
      next if (data[:original_value].to_s == data[:new_value].to_s)
    end
    changes_to_make[opt] = data[:new_value]
  end # editing_walkthru_state.each do |opt, data|

  return changes_to_make

end

#process_edits(pkg, changes_to_make) ⇒ void

This method returns an undefined value.

Make the changes that have been requested with an edit

Parameters:

  • pkg (D3::Package)

    the package we’re editing

  • changes_to_make (Hash)

    the changes we want to make



286
287
288
289
290
291
292
293
# File 'lib/d3/admin/edit.rb', line 286

def process_edits (pkg, changes_to_make)
  changes_to_make.each do |opt, new_val|
    setter = (opt.to_s + "=").to_sym
    pkg.send setter, new_val
  end
  pkg.save
  pkg.update_master_filename D3::Admin::Auth.rw_credentials(:dist)[:password] if changes_to_make[:filename]
end

#validate_cli_edits(cli_options) ⇒ Hash

Validate the desired edits from the CLI options

Parameters:

  • cli_options (OpenStruct)

    the options from the CLI

Returns:

  • (Hash)

    A hash of changes to make to the pkg. Keys are the option symbols from EDITING_OPTIONS, values are new values



203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/d3/admin/edit.rb', line 203

def validate_cli_edits (cli_options)
  changes_to_make = {}
  EDITING_OPTIONS.each do |opt|
    if cli_options[opt]
      opt_check = D3::Admin::OPTIONS[opt][:validate]
      if opt_check
        changes_to_make[opt] = D3::Admin::Validate.send(opt_check, cli_options[opt])
      else
        changes_to_make[opt] = cli_options[opt]
      end
    end # if @options[opt]
  end #.each do |opt|
  changes_to_make
end

#walkthru_menu_lines(editing_walkthru_state) ⇒ Array<String>

Regenerate the walkthru menu lines

Parameters:

  • editing_walkthru_state (Hash)

    the current state of the values being edited

Returns:

  • (Array<String>)

    the lines of the walkthru menu



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/d3/admin/edit.rb', line 161

def walkthru_menu_lines (editing_walkthru_state)

  display_lines = []
  EDITING_OPTIONS.each do |opt|
    # opt is the option symbol, like :reboot
    opt_def = D3::Admin::OPTIONS[opt]
    label = opt_def[:label]
    converter = opt_def[:display_conversion]

    # did the thing change?
    # compare the old and new either with .to_s and ==
    # or with the :compare proc defined in EDITING_OPTION_INFO
    if opt_def[:compare]
       option_didnt_change = (opt_def[:compare].call editing_walkthru_state[opt][:original_value], editing_walkthru_state[opt][:new_value])
    else
       option_didnt_change = (editing_walkthru_state[opt][:original_value].to_s ==  editing_walkthru_state[opt][:new_value].to_s)
    end

    # no change, so just display the orig value
    if option_didnt_change
      val_to_display = editing_walkthru_state[opt][:original_value_display]

    # But if the new val is different, convert it if needed, then show it as "orig => new"
    else
      new_value_display = converter ? converter.call(editing_walkthru_state[opt][:new_value]) : editing_walkthru_state[opt][:new_value]
      new_value_display = NONE if new_value_display.to_s.empty?
      val_to_display = "#{editing_walkthru_state[opt][:original_value_display]} => #{new_value_display}"
    end

    # make the line and add it to the array of lines
    display_lines << "#{label}: #{val_to_display}"
  end
  return display_lines
end