Class: ExchangeCmd

Inherits:
Object
  • Object
show all
Includes:
MrMurano::Verbose
Defined in:
lib/MrMurano/commands/exchange.rb

Overview

*** Business commands: Exchange Elements


Constant Summary collapse

STATUSABLE_RANK =
i[added available upgrade].freeze

Constants included from MrMurano::Verbose

MrMurano::Verbose::TABULARIZE_DATA_FORMAT_ERROR

Instance Method Summary collapse

Methods included from MrMurano::Verbose

ask_yes_no, #ask_yes_no, #assert, assert, cmd_confirm_delete!, #cmd_confirm_delete!, debug, #debug, dump_file_json, dump_file_plain, dump_file_yaml, #dump_output_file, #error, error, #error_file_format!, fancy_ticks, #fancy_ticks, #load_file_json, #load_file_plain, #load_file_yaml, #load_input_file, outf, #outf, #outformat_engine, #pluralize?, pluralize?, #prepare_hash_csv, #read_hashf!, #tabularize, tabularize, verbose, #verbose, warning, #warning, #whirly_interject, whirly_interject, #whirly_linger, whirly_linger, #whirly_msg, whirly_msg, #whirly_pause, whirly_pause, #whirly_start, whirly_start, #whirly_stop, whirly_stop, #whirly_unpause, whirly_unpause

Instance Method Details

#cmd_exchange_header_and_elems(elems, options) ⇒ Object



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
195
196
197
198
199
200
201
202
# File 'lib/MrMurano/commands/exchange.rb', line 167

def cmd_exchange_header_and_elems(elems, options)
  # MAYBE/2017-08-31: If you `-c outformat=json`, each Element is a
  # list of values, rather than a dictionary. Wouldn't the JSON be
  # easier to consume if each Element was a dict, rather than list?
  if options.idonly
    headers = i[elementId]
    elems = elems.map(&:elementId)
  elsif options.brief
    headers = i[elementId name]
    headers += [:status] unless options.added
    elems = elems.map { |elem| headers.map { |key| elem.send(key) } }
  elsif options.full
    headers = i[elementId name status type apiServiceName tiers tags actions markdown]
    all_hdrs = (elems[0] && elems[0].meta.keys) || []
    all_hdrs.each do |chk|
      headers.push(chk) unless headers.include?(chk)
    end
    elems = elems.map { |elem| headers.map { |key| elem.send(key) || '' } }
  elsif options.other
    # NOTE: Showing columns not displayed when --other not specified,
    #   except not showing :markdown, ever.
    headers = i[elementId type apiServiceName tiers tags actions]
    elems = cmd_exchange_header_and_elems_others(elems)
  else
    # 2017-08-28: There are 9 keys, and one of them -- :markdown -- is a
    # lot of text, so rather than, e.g., elems[0].meta.keys, be selective.
    headers = i[elementId name]
    headers += [:type] if options.elem_type
    headers += [:status] unless options.added
    headers += [:description]
    width_avail = MrMurano::Pretties.width_last_column(headers, elems)
    elems = cmd_exchange_header_and_elems_default(headers, elems, width_avail)
  end
  headers.delete(:type) if options.elem_type == false
  [headers, elems]
end

#cmd_exchange_header_and_elems_default(headers, elems, width_avail) ⇒ Object



157
158
159
160
161
162
163
164
165
# File 'lib/MrMurano/commands/exchange.rb', line 157

def cmd_exchange_header_and_elems_default(headers, elems, width_avail)
  elems.map do |elem|
    headers.map do |key|
      full = elem.send(key)
      next(full) if width_avail.nil? || key != :description || full.empty?
      MrMurano::Pretties.split_text_on_whitespace(full, width_avail)
    end
  end
end

#cmd_exchange_header_and_elems_others(elems) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/MrMurano/commands/exchange.rb', line 141

def cmd_exchange_header_and_elems_others(elems)
  elems.map do |elem|
    elem_actions = elem.actions.nil? && [] || elem.actions.map do |action|
      action.map { |key, val| "#{key}: #{val}" }.join("\n")
    end
    [
      elem.elementId,
      elem.type,
      elem.apiServiceName,
      elem.tiers.join("\n"),
      elem.tags.join("\n"),
      elem_actions.join("\n"),
    ]
  end
end

#command_exchange_help(cmd) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/MrMurano/commands/exchange.rb', line 21

def command_exchange_help(cmd)
  cmd.syntax = %(murano exchange)
  cmd.summary = %(IoT Marketplace Exchange commands)
  cmd.description = %(
    Commands for working with IoT Marketplace.
  ).strip
  cmd.project_not_required = true
  cmd.subcmdgrouphelp = true

  cmd.action do |_args, _options|
    ::Commander::UI.enable_paging unless $cfg['tool.no-page']
    say MrMurano::SubCmdGroupHelp.new(cmd).get_help
  end
end

#command_exchange_list(cmd) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/MrMurano/commands/exchange.rb', line 36

def command_exchange_list(cmd)
  cmd.syntax = %(murano exchange list [--options] [<name-or-ID>])
  cmd.summary = %(List Exchange Elements)
  cmd.description = %(
List Exchange Elements, either all of them, or those that are purchased or available.

Each Exchange Element is identified by an Element ID and a name.

Element status:

- added       An Element that has been added to and enabled for your Business

- available   An Element that can be added to and enabled for your Business

- available*  An Element that you can use if you upgrade your Business tier

  ).strip
  cmd.project_not_required = true

  cmd_table_output_add_options(cmd)

  cmd.option '--[no-]added', 'Only show Elements that have been added to the Business'
  cmd.option '--[no-]elem-type', 'Show element "type"'
  cmd.option '--[no-]full', 'Show all fields'
  cmd.option '--[no-]other', 'Show other fields: like type, tiers, tags, and action, and apiServiceName'

  # Add --id and --name options.
  cmd_options_add_id_and_name(cmd)

  cmd.action do |args, options|
    cmd.verify_arg_count!(args, 1)
    cmd_defaults_id_and_name(options)

    xchg = MrMurano::Exchange.new
    xchg.must_business_id!

    show = filter_elements(xchg, options, args[0])
    sorted = sort_elements(show)

    headers, pruned = cmd_exchange_header_and_elems(sorted, options)

    io = File.open(options.output, 'w') if options.output
    xchg.outf(pruned, io) do |item, ios|
      if options.idonly
        ios.puts item
      else
        ios.puts "Found #{pruned.length} elements."
        xchg.tabularize(
          {
            headers: headers.map(&:to_s),
            rows: item,
          },
          ios,
        )
      end
    end
    io.close unless io.nil?
  end
end

#command_exchange_purchase(cmd) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/MrMurano/commands/exchange.rb', line 204

def command_exchange_purchase(cmd)
  cmd.syntax = %(murano exchange purchase [--options] <name-or-ID>)
  cmd.summary = %(Add an Exchange Element to your Business)
  cmd.description = %(
    Add an Exchange Element to your Business.
  ).strip
  # It feels a little weird to not require a project, but all
  # we need is the Business ID; this action does not apply to
  # solutions.
  cmd.project_not_required = true

  # Add --id and --name options.
  cmd_options_add_id_and_name(cmd)

  cmd.action do |args, options|
    cmd.verify_arg_count!(args, 1, ['Missing Element name or ID'])
    cmd_defaults_id_and_name(options)

    xchg = MrMurano::Exchange.new
    xchg.must_business_id!

    # If the user specifies filter_id, we could try to fetch that Element
    # directly (e.g., by calling exchange/<bizId>/element/<elemId>),
    # but the response doesn't specify if the Element is purchased or not.
    # So we grab everything from /element/ and /purchase/.

    elems, _available, purchased = find_elements(xchg, options, args[0])

    elems_must_found_one!(elems, xchg)
    if purchased.length == 1
      # I.e., elems.status == :added
      xchg.warning(
        'The specified element has already been purchased: ' \
        "#{xchg.fancy_ticks(purchased[0].name)} (#{purchased[0].elementId})"
      )
      exit 2
    elsif elems.first.status == :upgrade
      xchg.warning('Please upgrade your Business to add this Element. Visit:')
      xchg.warning('  https://www.exosite.io/business/settings/upgrade')
      exit 2
    end

    xchg.purchase(elems.first.elementId)
  end
end

#elems_must_found_one!(elems, xchg) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/MrMurano/commands/exchange.rb', line 250

def elems_must_found_one!(elems, xchg)
  if elems.length > 1
    idents = elems.map { |elem| "#{elem.elementId}: #{xchg.fancy_ticks(elem.name)}" }
    xchg.warning(
      "Please be more specific: More than one matching element was found:\n  " \
      "#{idents.join("\n  ")}"
    )
    exit 2
  elsif elems.empty?
    xchg.warning('No matching element was found.')
    exit 2
  end
  elems.first
end

#filter_elements(xchg, options, term) ⇒ Object



117
118
119
120
121
122
123
124
125
126
# File 'lib/MrMurano/commands/exchange.rb', line 117

def filter_elements(xchg, options, term)
  elems, available, purchased = find_elements(xchg, options, term)
  if options.added.nil?
    elems
  elsif options.added
    purchased
  else
    available
  end
end

#find_elements(xchg, options, term, skip_purchased: false) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/MrMurano/commands/exchange.rb', line 96

def find_elements(xchg, options, term, skip_purchased: false)
  filter_id = nil
  filter_name = nil
  filter_fuzzy = nil
  if term
    if options.id
      filter_id = term
    elsif options.name
      filter_name = term
    else
      filter_fuzzy = term
    end
  end
  xchg.elements(
    filter_id: filter_id,
    filter_name: filter_name,
    filter_fuzzy: filter_fuzzy,
    skip_purchased: skip_purchased,
  )
end

#sort_elements(elems) ⇒ Object



130
131
132
133
134
135
136
137
138
139
# File 'lib/MrMurano/commands/exchange.rb', line 130

def sort_elements(elems)
  elems.sort do |lhs, rhs|
    if lhs.statusable != rhs.statusable
      next(
        STATUSABLE_RANK.index(lhs.statusable) <=> STATUSABLE_RANK.index(rhs.statusable)
      )
    end
    lhs.name <=> rhs.name
  end
end