aspera-cli 4.19.0 → 4.21.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +46 -0
  4. data/CONTRIBUTING.md +18 -4
  5. data/README.md +886 -510
  6. data/bin/asession +27 -20
  7. data/examples/build_exec +65 -76
  8. data/examples/build_exec_rubyc +40 -0
  9. data/examples/get_proto_file.rb +7 -0
  10. data/lib/aspera/agent/alpha.rb +18 -24
  11. data/lib/aspera/agent/base.rb +2 -18
  12. data/lib/aspera/agent/connect.rb +34 -15
  13. data/lib/aspera/agent/direct.rb +44 -54
  14. data/lib/aspera/agent/httpgw.rb +2 -3
  15. data/lib/aspera/agent/node.rb +11 -21
  16. data/lib/aspera/agent/{trsdk.rb → transferd.rb} +27 -51
  17. data/lib/aspera/api/alee.rb +15 -0
  18. data/lib/aspera/api/aoc.rb +139 -105
  19. data/lib/aspera/api/ats.rb +1 -1
  20. data/lib/aspera/api/cos_node.rb +1 -1
  21. data/lib/aspera/api/httpgw.rb +15 -10
  22. data/lib/aspera/api/node.rb +70 -32
  23. data/lib/aspera/ascmd.rb +56 -48
  24. data/lib/aspera/ascp/installation.rb +166 -70
  25. data/lib/aspera/ascp/management.rb +30 -8
  26. data/lib/aspera/assert.rb +10 -5
  27. data/lib/aspera/cli/formatter.rb +166 -162
  28. data/lib/aspera/cli/hints.rb +2 -1
  29. data/lib/aspera/cli/info.rb +12 -10
  30. data/lib/aspera/cli/main.rb +28 -13
  31. data/lib/aspera/cli/manager.rb +7 -2
  32. data/lib/aspera/cli/plugin.rb +17 -31
  33. data/lib/aspera/cli/plugins/alee.rb +3 -3
  34. data/lib/aspera/cli/plugins/aoc.rb +246 -208
  35. data/lib/aspera/cli/plugins/ats.rb +16 -14
  36. data/lib/aspera/cli/plugins/config.rb +154 -94
  37. data/lib/aspera/cli/plugins/console.rb +3 -3
  38. data/lib/aspera/cli/plugins/cos.rb +1 -0
  39. data/lib/aspera/cli/plugins/faspex.rb +15 -23
  40. data/lib/aspera/cli/plugins/faspex5.rb +64 -50
  41. data/lib/aspera/cli/plugins/faspio.rb +2 -2
  42. data/lib/aspera/cli/plugins/httpgw.rb +1 -1
  43. data/lib/aspera/cli/plugins/node.rb +174 -109
  44. data/lib/aspera/cli/plugins/orchestrator.rb +14 -13
  45. data/lib/aspera/cli/plugins/preview.rb +8 -9
  46. data/lib/aspera/cli/plugins/server.rb +5 -9
  47. data/lib/aspera/cli/plugins/shares.rb +2 -2
  48. data/lib/aspera/cli/sync_actions.rb +2 -2
  49. data/lib/aspera/cli/transfer_agent.rb +12 -14
  50. data/lib/aspera/cli/transfer_progress.rb +37 -17
  51. data/lib/aspera/cli/version.rb +1 -1
  52. data/lib/aspera/command_line_builder.rb +4 -5
  53. data/lib/aspera/coverage.rb +13 -1
  54. data/lib/aspera/environment.rb +75 -25
  55. data/lib/aspera/faspex_gw.rb +2 -2
  56. data/lib/aspera/json_rpc.rb +1 -1
  57. data/lib/aspera/keychain/macos_security.rb +7 -12
  58. data/lib/aspera/log.rb +3 -4
  59. data/lib/aspera/node_simulator.rb +230 -112
  60. data/lib/aspera/oauth/base.rb +64 -83
  61. data/lib/aspera/oauth/factory.rb +52 -6
  62. data/lib/aspera/oauth/generic.rb +4 -8
  63. data/lib/aspera/oauth/jwt.rb +6 -3
  64. data/lib/aspera/oauth/url_json.rb +1 -2
  65. data/lib/aspera/oauth/web.rb +5 -2
  66. data/lib/aspera/persistency_action_once.rb +16 -8
  67. data/lib/aspera/persistency_folder.rb +20 -2
  68. data/lib/aspera/preview/generator.rb +1 -1
  69. data/lib/aspera/preview/utils.rb +11 -17
  70. data/lib/aspera/products/alpha.rb +30 -0
  71. data/lib/aspera/products/connect.rb +48 -0
  72. data/lib/aspera/products/other.rb +82 -0
  73. data/lib/aspera/products/transferd.rb +54 -0
  74. data/lib/aspera/rest.rb +116 -87
  75. data/lib/aspera/secret_hider.rb +2 -2
  76. data/lib/aspera/ssh.rb +31 -24
  77. data/lib/aspera/transfer/faux_file.rb +4 -4
  78. data/lib/aspera/transfer/parameters.rb +16 -17
  79. data/lib/aspera/transfer/spec.rb +12 -12
  80. data/lib/aspera/transfer/spec.yaml +22 -20
  81. data/lib/aspera/transfer/sync.rb +2 -10
  82. data/lib/aspera/transfer/uri.rb +3 -3
  83. data/lib/aspera/uri_reader.rb +1 -1
  84. data/lib/aspera/web_auth.rb +166 -17
  85. data/lib/aspera/web_server_simple.rb +4 -3
  86. data/lib/transferd_pb.rb +86 -0
  87. data/lib/transferd_services_pb.rb +84 -0
  88. data.tar.gz.sig +0 -0
  89. metadata +58 -22
  90. metadata.gz.sig +0 -0
  91. data/lib/aspera/ascp/products.rb +0 -156
@@ -37,7 +37,8 @@ module Aspera
37
37
  # sub path in url for public link delivery
38
38
  PUB_LINK_EXTERNAL_MATCH = 'external_deliveries/'
39
39
  STANDARD_PATH = '/aspera/faspex'
40
- private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH])
40
+ HEADER_FASPEX_VERSION = 'X-IBM-Aspera'
41
+ private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH HEADER_FASPEX_VERSION])
41
42
 
42
43
  class << self
43
44
  def detect(address_or_url)
@@ -58,7 +59,7 @@ module Aspera
58
59
  # 4.x
59
60
  next unless result[:http].body.start_with?('<?xml')
60
61
  res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
61
- Log.log.debug{"version: #{result[:http]['X-IBM-Aspera']}"}
62
+ Log.log.debug{"version: #{result[:http][HEADER_FASPEX_VERSION]}"}
62
63
  version = res_s['XRD']['application']['version']
63
64
  # take redirect if any
64
65
  return {
@@ -95,7 +96,7 @@ module Aspera
95
96
  result = {
96
97
  base_url: "#{public_uri.scheme}://#{public_uri.host}#{port_add}#{base}",
97
98
  subpath: subpath,
98
- query: Rest.decode_query(public_uri.query)
99
+ query: Rest.query_to_h(public_uri.query)
99
100
  }
100
101
  Log.log.debug{Log.dump('link data', result)}
101
102
  return result
@@ -246,7 +247,7 @@ module Aspera
246
247
  delivery_info[:source_paths_list] = transfer.source_list.join("\r\n")
247
248
  api_public_link = Rest.new(base_url: link_data[:base_url])
248
249
  # Hum, as this does not always work (only user, but not dropbox), we get the javascript and need hack
249
- # pkg_created=api_public_link.create(create_path,package_create_params)[:data]
250
+ # pkg_created=api_public_link.create(create_path,package_create_params)
250
251
  # so extract data from javascript
251
252
  package_creation_data = api_public_link.call(
252
253
  operation: 'POST',
@@ -304,20 +305,14 @@ module Aspera
304
305
  # authenticated user
305
306
  delivery_info['sources'] ||= [{'paths' => []}]
306
307
  first_source = delivery_info['sources'].first
307
- first_source['paths'].push(*transfer.source_list)
308
+ first_source['paths'].concat(transfer.source_list)
308
309
  source_id = instance_identifier(as_option: :remote_source) do |field, value|
309
310
  Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
310
- source_list = api_v3.call(operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'})[:data]['items']
311
+ source_list = api_v3.read('source_shares')['items']
311
312
  self.class.get_source_id_by_name(value, source_list)
312
313
  end
313
314
  first_source['id'] = source_id.to_i unless source_id.nil?
314
- pkg_created = api_v3.call(
315
- operation: 'POST',
316
- subpath: 'send',
317
- headers: {'Accept' => 'application/json'},
318
- body: package_create_params,
319
- body_type: :json
320
- )[:data]
315
+ pkg_created = api_v3.create('send', package_create_params)
321
316
  if first_source.key?('id')
322
317
  # no transfer spec if remote source: handled by faspex
323
318
  return {data: [pkg_created['links']['status']], type: :value_list, name: 'link'}
@@ -437,7 +432,7 @@ module Aspera
437
432
  end
438
433
  when :source
439
434
  command_source = options.get_next_command(%i[list info node])
440
- source_list = api_v3.call(operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'})[:data]['items']
435
+ source_list = api_v3.read('source_shares')['items']
441
436
  case command_source
442
437
  when :list
443
438
  return {type: :object_list, data: source_list}
@@ -446,7 +441,9 @@ module Aspera
446
441
  Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
447
442
  self.class.get_source_id_by_name(value, source_list)
448
443
  end.to_i
449
- source_name = source_list.find{|i|i['id'].eql?(source_id)}['name']
444
+ selected_source = source_list.find{|i|i['id'].eql?(source_id)}
445
+ raise 'No such source' if selected_source.nil?
446
+ source_name = selected_source['name']
450
447
  source_hash = options.get_option(:storage, mandatory: true)
451
448
  # check value of option
452
449
  Aspera.assert_type(source_hash, Hash, exception_class: Cli::Error){'storage option'}
@@ -479,13 +476,13 @@ module Aspera
479
476
  end
480
477
  end
481
478
  when :me
482
- my_info = api_v3.call(operation: 'GET', subpath: 'me', headers: {'Accept' => 'application/json'})[:data]
479
+ my_info = api_v3.read('me')
483
480
  return {data: my_info, type: :single_object}
484
481
  when :dropbox
485
482
  command_pkg = options.get_next_command([:list])
486
483
  case command_pkg
487
484
  when :list
488
- dropbox_list = api_v3.call(operation: 'GET', subpath: 'dropboxes', headers: {'Accept' => 'application/json'})[:data]
485
+ dropbox_list = api_v3.read('dropboxes')
489
486
  return {type: :object_list, data: dropbox_list['items'], fields: %w[name id description can_read can_write]}
490
487
  end
491
488
  when :v4
@@ -509,12 +506,7 @@ module Aspera
509
506
  return entity_action(api_v4, "#{pkg_box_type}/#{pkg_box_id}/packages")
510
507
  end
511
508
  when :address_book
512
- result = api_v3.call(
513
- operation: 'GET',
514
- subpath: 'address-book',
515
- headers: {'Accept' => 'application/json'},
516
- query: {'format' => 'json', 'count' => 100_000}
517
- )[:data]
509
+ result = api_v3.read('address-book', {'format' => 'json', 'count' => 100_000})
518
510
  formatter.display_status("users: #{result['itemsPerPage']}/#{result['totalResults']}, start:#{result['startIndex']}")
519
511
  users = result['entry']
520
512
  # add missing entries
@@ -34,12 +34,14 @@ module Aspera
34
34
  # endpoint for authentication API
35
35
  PATH_AUTH = 'auth'
36
36
  PATH_HEALTH = 'configuration/ping'
37
+ PATH_API_DETECT = "#{PATH_API_V5}/#{PATH_HEALTH}"
37
38
  PER_PAGE_DEFAULT = 100
38
39
  # OAuth methods supported
39
40
  STD_AUTH_TYPES = %i[web jwt boot].freeze
40
41
  HEADER_ITERATION_TOKEN = 'X-Aspera-Next-Iteration-Token'
42
+ HEADER_FASPEX_VERSION = 'X-IBM-Aspera'
41
43
  private_constant(*%i[JOB_RUNNING RECIPIENT_TYPES PACKAGE_TERMINATED PATH_HEALTH API_LIST_MAILBOX_TYPES PACKAGE_SEND_FROM_REMOTE_SOURCE PER_PAGE_DEFAULT
42
- STD_AUTH_TYPES])
44
+ STD_AUTH_TYPES HEADER_ITERATION_TOKEN HEADER_FASPEX_VERSION])
43
45
  class << self
44
46
  def application_name
45
47
  'Faspex'
@@ -55,15 +57,14 @@ module Aspera
55
57
  # Faspex is always HTTPS
56
58
  next unless base_url.start_with?('https://')
57
59
  api = Rest.new(base_url: base_url, redirect_max: 1)
58
- path_api_detect = "#{PATH_API_V5}/#{PATH_HEALTH}"
59
- result = api.read(path_api_detect)
60
- next unless result[:http].code.start_with?('2') && result[:http].body.strip.empty?
60
+ response = api.call(operation: 'GET', subpath: PATH_API_DETECT)[:http]
61
+ next unless response.code.start_with?('2') && response.body.strip.empty?
61
62
  # end is at -1, and subtract 1 for "/"
62
- url_length = -2 - path_api_detect.length
63
+ url_length = -2 - PATH_API_DETECT.length
63
64
  # take redirect if any
64
65
  return {
65
- version: result[:http]['x-ibm-aspera'] || '5',
66
- url: result[:http].uri.to_s[0..url_length]
66
+ version: response[HEADER_FASPEX_VERSION] || '5',
67
+ url: response.uri.to_s[0..url_length]
67
68
  }
68
69
  rescue StandardError => e
69
70
  error = e
@@ -133,8 +134,8 @@ module Aspera
133
134
  case auth_type
134
135
  when :public_link
135
136
  # resolve any redirect
136
- @faspex5_api_base_url = Rest.new(base_url: @faspex5_api_base_url, redirect_max: 3).read('')[:http].uri.to_s
137
- encoded_context = Rest.decode_query(URI.parse(@faspex5_api_base_url).query)['context']
137
+ @faspex5_api_base_url = Rest.new(base_url: @faspex5_api_base_url, redirect_max: 3).call(operation: 'GET')[:http].uri.to_s
138
+ encoded_context = Rest.query_to_h(URI.parse(@faspex5_api_base_url).query)['context']
138
139
  raise 'Bad faspex5 public link, missing context in query' if encoded_context.nil?
139
140
  # public link information (allowed usage)
140
141
  @pub_link_context = JSON.parse(Base64.decode64(encoded_context))
@@ -182,7 +183,7 @@ module Aspera
182
183
  else Aspera.error_unexpected_value(auth_type)
183
184
  end
184
185
  # in case user wants to use HTTPGW tell transfer agent how to get address
185
- transfer.httpgw_url_cb = lambda { @api_v5.read('account')[:data]['gateway_url'] }
186
+ transfer.httpgw_url_cb = lambda { @api_v5.read('account')['gateway_url'] }
186
187
  end
187
188
 
188
189
  # if recipient is just an email, then convert to expected API hash : name and type
@@ -198,7 +199,7 @@ module Aspera
198
199
  parameters['recipients'].map! do |recipient_data|
199
200
  # if just a string, make a general lookup and build expected name/type hash
200
201
  if recipient_data.is_a?(String)
201
- matched = @api_v5.lookup_by_name('contacts', recipient_data, {context: 'packages', type: Rest.array_params(recipient_types)})
202
+ matched = @api_v5.lookup_by_name('contacts', recipient_data, query: {context: 'packages', type: Rest.array_params(recipient_types)})
202
203
  recipient_data = {
203
204
  name: matched['name'],
204
205
  recipient_type: matched['type']
@@ -213,22 +214,22 @@ module Aspera
213
214
  def wait_package_status(id, status_list: PACKAGE_TERMINATED)
214
215
  total_sent = false
215
216
  loop do
216
- status = @api_v5.read("packages/#{id}/upload_details")[:data]
217
+ status = @api_v5.read("packages/#{id}/upload_details")
217
218
  status['id'] = id
218
219
  # user asked to not follow
219
220
  return status if status_list.nil?
220
221
  if status['upload_status'].eql?('submitted')
221
- config.progress_bar&.event(session_id: nil, type: :pre_start, info: status['upload_status'])
222
+ config.progress_bar&.event(:pre_start, session_id: nil, info: status['upload_status'])
222
223
  elsif !total_sent
223
- config.progress_bar&.event(session_id: id, type: :session_start)
224
- config.progress_bar&.event(session_id: id, type: :session_size, info: status['bytes_total'].to_i)
224
+ config.progress_bar&.event(:session_start, session_id: id)
225
+ config.progress_bar&.event(:session_size, session_id: id, info: status['bytes_total'].to_i)
225
226
  total_sent = true
226
227
  else
227
- config.progress_bar&.event(session_id: id, type: :transfer, info: status['bytes_written'].to_i)
228
+ config.progress_bar&.event(:transfer, session_id: id, info: status['bytes_written'].to_i)
228
229
  end
229
230
  if status_list.include?(status['upload_status'])
230
231
  # if status['upload_status'].eql?('completed')
231
- config.progress_bar&.event(session_id: id, type: :end)
232
+ config.progress_bar&.event(:end, session_id: id)
232
233
  return status
233
234
  # end
234
235
  end
@@ -236,14 +237,18 @@ module Aspera
236
237
  end
237
238
  end
238
239
 
240
+ # @param [Srting] job identifier
241
+ # @return [Hash] result of API call for job status
239
242
  def wait_for_job(job_id)
243
+ result = nil
240
244
  loop do
241
- status = @api_v5.read("jobs/#{job_id}", {type: :formatted})[:data]
242
- return status unless JOB_RUNNING.include?(status['status'])
243
- formatter.long_operation_running(status['status'])
245
+ result = @api_v5.read("jobs/#{job_id}", {type: :formatted})
246
+ break unless JOB_RUNNING.include?(result['status'])
247
+ formatter.long_operation_running(result['status'])
244
248
  sleep(0.5)
245
249
  end
246
- Aspera.error_unreachable_line
250
+ formatter.long_operation_terminated
251
+ return result
247
252
  end
248
253
 
249
254
  # Get a (full or partial) list of all entities of a given type with query: offset/limit
@@ -251,9 +256,10 @@ module Aspera
251
256
  # @param query [Hash,nil] additional query parameters
252
257
  # @param real_path [String] real path if it's n ot just the type
253
258
  # @param item_list_key [String] key in the result to get the list of items
254
- def list_entities(type:, real_path: nil, item_list_key: nil, query: {})
259
+ def list_entities(type:, real_path: nil, item_list_key: nil, query: nil)
255
260
  Log.log.trace1{"list_entities t=#{type} p=#{real_path} k=#{item_list_key} q=#{query}"}
256
261
  type = type.to_s if type.is_a?(Symbol)
262
+ query = {} if query.nil?
257
263
  Aspera.assert_type(type, String)
258
264
  Aspera.assert_type(query, Hash)
259
265
  item_list_key = type if item_list_key.nil?
@@ -266,7 +272,7 @@ module Aspera
266
272
  query = {'limit'=> PER_PAGE_DEFAULT}.merge(query)
267
273
  loop do
268
274
  query['offset'] = offset
269
- page_result = @api_v5.read(real_path, query)[:data]
275
+ page_result = @api_v5.read(real_path, query)
270
276
  Aspera.assert_type(page_result[item_list_key], Array)
271
277
  result.concat(page_result[item_list_key])
272
278
  # reach the limit set by user ?
@@ -280,6 +286,7 @@ module Aspera
280
286
  offset += page_result[item_list_key].length
281
287
  formatter.long_operation_running
282
288
  end
289
+ formatter.long_operation_terminated
283
290
  return result
284
291
  end
285
292
 
@@ -356,7 +363,7 @@ module Aspera
356
363
  package_ids = [package_ids] unless package_ids.is_a?(Array)
357
364
  Aspera.assert_type(package_ids, Array){'Expecting a single package id or a list of ids'}
358
365
  Aspera.assert(package_ids.all?(String)){'Package id shall be String'}
359
- # packages = package_ids.map{|pkg_id|@api_v5.read("packages/#{pkg_id}")[:data]}
366
+ # packages = package_ids.map{|pkg_id|@api_v5.read("packages/#{pkg_id}")}
360
367
  packages = package_ids.map{|pkg_id|{'id'=>pkg_id}}
361
368
  end
362
369
  result_transfer = []
@@ -439,6 +446,7 @@ module Aspera
439
446
  end
440
447
  query.delete('iteration_token')
441
448
  end
449
+ formatter.long_operation_terminated
442
450
  return {type: :object_list, data: all_items}
443
451
  end
444
452
 
@@ -450,7 +458,7 @@ module Aspera
450
458
  end
451
459
  case command
452
460
  when :show
453
- return {type: :single_object, data: @api_v5.read("packages/#{package_id}")[:data]}
461
+ return {type: :single_object, data: @api_v5.read("packages/#{package_id}")}
454
462
  when :browse
455
463
  location = case options.get_option(:box)
456
464
  when 'inbox' then 'received'
@@ -486,7 +494,7 @@ module Aspera
486
494
  }]
487
495
  end
488
496
  normalize_recipients(parameters)
489
- package = @api_v5.create('packages', parameters)[:data]
497
+ package = @api_v5.create('packages', parameters)
490
498
  shared_folder = options.get_option(:shared_folder)
491
499
  if shared_folder.nil?
492
500
  # send from local files
@@ -511,7 +519,7 @@ module Aspera
511
519
  end
512
520
  transfer_request = {shared_folder_id: shared_folder, paths: transfer.source_list}
513
521
  # start remote transfer and get first status
514
- result = @api_v5.create("packages/#{package['id']}/remote_transfer", transfer_request)[:data]
522
+ result = @api_v5.create("packages/#{package['id']}/remote_transfer", transfer_request)
515
523
  result['id'] = package['id']
516
524
  unless result['status'].eql?('completed')
517
525
  formatter.display_status("Package #{package['id']}")
@@ -551,9 +559,10 @@ module Aspera
551
559
  id_as_arg = 'type'
552
560
  when :accounts
553
561
  display_fields = Formatter.all_but('user_profile_data_attributes')
562
+ available_commands.push(:reset_password)
554
563
  when :oauth_clients
555
564
  display_fields = Formatter.all_but('public_key')
556
- adm_api = Rest.new(**@api_v5.params.merge(base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}"))
565
+ adm_api = Rest.new(**@api_v5.params, base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}")
557
566
  when :shared_inboxes, :workgroups
558
567
  available_commands.push(:members, :saml_groups, :invite_external_collaborator)
559
568
  res_id_query = {'all': true}
@@ -597,7 +606,7 @@ module Aspera
597
606
  creation_payload = value_create_modify(command: res_command, type: [Hash, String])
598
607
  creation_payload = {'email_address' => creation_payload} if creation_payload.is_a?(String)
599
608
  res_path = "#{res_type}/#{shared_inbox_id}/external_collaborator"
600
- result = adm_api.create(res_path, creation_payload)[:data]
609
+ result = adm_api.create(res_path, creation_payload)
601
610
  formatter.display_status(result['message'])
602
611
  result = lookup_entity_by_field(
603
612
  type: 'members',
@@ -612,8 +621,7 @@ module Aspera
612
621
  list_key = res_command.to_s
613
622
  list_key = 'groups' if res_command.eql?(:saml_groups)
614
623
  sub_command = options.get_next_command(%i[create list modify delete])
615
- if sub_command.eql?(:create) && options.get_option(:value).nil?
616
- raise "use option 'value' to provide saml group_id and access (refer to API)" unless res_command.eql?(:members)
624
+ if sub_command.eql?(:create) && res_command.eql?(:members)
617
625
  # first arg is one user name or list of users
618
626
  users = options.get_next_argument('user id, %name:, or Array')
619
627
  users = [users] unless users.is_a?(Array)
@@ -630,8 +638,7 @@ module Aspera
630
638
  end
631
639
  end
632
640
  access = options.get_next_argument('level', mandatory: false, accept_list: %i[submit_only standard shared_inbox_admin], default: :standard)
633
- # TODO: unshift to command line parameters instead of using deprecated option "value"
634
- options.set_option(:value, {user: users.map{|u|{id: u, access: access}}})
641
+ options.unshift_next_argument({user: users.map{|u|{id: u, access: access}}})
635
642
  end
636
643
  return entity_command(sub_command, adm_api, res_path, item_list_key: list_key) do |field, value|
637
644
  lookup_entity_by_field(
@@ -640,7 +647,12 @@ module Aspera
640
647
  value: value,
641
648
  query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})})['id']
642
649
  end
650
+ when :reset_password
651
+ contact_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value, query: res_id_query)['id']}
652
+ adm_api.create("#{res_type}/#{contact_id}/reset_password", {})
653
+ return Main.result_status('password reset, user shall check email')
643
654
  end
655
+ Aspera.error_unreachable_line
644
656
  end
645
657
 
646
658
  def execute_admin
@@ -653,43 +665,45 @@ module Aspera
653
665
  when *ADMIN_RESOURCES
654
666
  return execute_resource(command)
655
667
  when :clean_deleted
656
- delete_data = value_create_modify(command: command, default: {days_before_deleting_package_records: 365})
668
+ delete_data = value_create_modify(command: command, default: {})
669
+ delete_data = @api_v5.read('configuration').slice('days_before_deleting_package_records') if delete_data.empty?
657
670
  res = @api_v5.create('internal/packages/clean_deleted', delete_data)
658
- return {type: :single_object, data: res[:data]}
671
+ return {type: :single_object, data: res}
659
672
  when :events
660
673
  event_type = options.get_next_command(%i[application webhook])
661
674
  case event_type
662
675
  when :application
663
- return {type: :object_list, data: list_entities(type: 'application_events'), fields: %w[event_type created_at application user.name]}
676
+ return {type: :object_list, data: list_entities(type: 'application_events', query: query_read_delete),
677
+ fields: %w[event_type created_at application user.name]}
664
678
  when :webhook
665
- return {type: :object_list, data: list_entities(type: 'all_webhooks_events', item_list_key: 'events')}
679
+ return {type: :object_list, data: list_entities(type: 'all_webhooks_events', query: query_read_delete, item_list_key: 'events')}
666
680
  end
667
681
  when :configuration
668
682
  conf_path = 'configuration'
669
683
  conf_cmd = options.get_next_command(%i[show modify])
670
684
  case conf_cmd
671
685
  when :show
672
- return { type: :single_object, data: @api_v5.read(conf_path)[:data] }
686
+ return { type: :single_object, data: @api_v5.read(conf_path) }
673
687
  when :modify
674
- return { type: :single_object, data: @api_v5.update(conf_path, value_create_modify(command: conf_cmd))[:data] }
688
+ return { type: :single_object, data: @api_v5.update(conf_path, value_create_modify(command: conf_cmd)) }
675
689
  end
676
690
  when :smtp
677
691
  smtp_path = 'configuration/smtp'
678
692
  smtp_cmd = options.get_next_command(%i[show create modify delete test])
679
693
  case smtp_cmd
680
694
  when :show
681
- return { type: :single_object, data: @api_v5.read(smtp_path)[:data] }
695
+ return { type: :single_object, data: @api_v5.read(smtp_path) }
682
696
  when :create
683
- return { type: :single_object, data: @api_v5.create(smtp_path, value_create_modify(command: smtp_cmd))[:data] }
697
+ return { type: :single_object, data: @api_v5.create(smtp_path, value_create_modify(command: smtp_cmd)) }
684
698
  when :modify
685
- return { type: :single_object, data: @api_v5.update(smtp_path, value_create_modify(command: smtp_cmd))[:data] }
699
+ return { type: :single_object, data: @api_v5.update(smtp_path, value_create_modify(command: smtp_cmd)) }
686
700
  when :delete
687
- @api_v5.delete(smtp_path)[:data]
701
+ @api_v5.delete(smtp_path)
688
702
  return Main.result_status('SMTP configuration deleted')
689
703
  when :test
690
704
  test_data = options.get_next_argument('Email or test data, see API')
691
705
  test_data = {test_email_recipient: test_data} if test_data.is_a?(String)
692
- creation = @api_v5.create(File.join(smtp_path, 'test'), test_data)[:data]
706
+ creation = @api_v5.create(File.join(smtp_path, 'test'), test_data)
693
707
  result = wait_for_job(creation['job_id'])
694
708
  result['serialized_args'] = JSON.parse(result['serialized_args']) rescue result['serialized_args']
695
709
  return { type: :single_object, data: result }
@@ -704,11 +718,11 @@ module Aspera
704
718
  set_api unless command.eql?(:postprocessing)
705
719
  case command
706
720
  when :version
707
- return { type: :single_object, data: @api_v5.read('version')[:data] }
721
+ return { type: :single_object, data: @api_v5.read('version') }
708
722
  when :health
709
723
  nagios = Nagios.new
710
724
  begin
711
- result = Rest.new(base_url: @faspex5_api_base_url).read('health')[:data]
725
+ result = Rest.new(base_url: @faspex5_api_base_url).read('health')
712
726
  result.each do |k, v|
713
727
  nagios.add_ok(k, v.to_s)
714
728
  end
@@ -719,11 +733,11 @@ module Aspera
719
733
  when :user
720
734
  case options.get_next_command(%i[account profile])
721
735
  when :account
722
- return { type: :single_object, data: @api_v5.read('account')[:data] }
736
+ return { type: :single_object, data: @api_v5.read('account') }
723
737
  when :profile
724
738
  case options.get_next_command(%i[show modify])
725
739
  when :show
726
- return { type: :single_object, data: @api_v5.read('account/preferences')[:data] }
740
+ return { type: :single_object, data: @api_v5.read('account/preferences') }
727
741
  when :modify
728
742
  @api_v5.update('account/preferences', options.get_next_argument('modified parameters', validation: Hash))
729
743
  return Main.result_status('modified')
@@ -734,7 +748,7 @@ module Aspera
734
748
  when :packages
735
749
  return package_action
736
750
  when :shared_folders
737
- all_shared_folders = @api_v5.read('shared_folders')[:data]['shared_folders']
751
+ all_shared_folders = @api_v5.read('shared_folders')['shared_folders']
738
752
  case options.get_next_command(%i[list browse])
739
753
  when :list
740
754
  return {type: :object_list, data: all_shared_folders}
@@ -758,7 +772,7 @@ module Aspera
758
772
  when :create
759
773
  return do_bulk_operation(command: invitation_command, descr: 'data') do |params|
760
774
  invitation_endpoint = params.key?('recipient_name') ? 'public_invitations' : 'invitations'
761
- @api_v5.create(invitation_endpoint, params)[:data]
775
+ @api_v5.create(invitation_endpoint, params)
762
776
  end
763
777
  when :resend
764
778
  @api_v5.create("#{invitation_endpoint}/#{instance_identifier}/resend")
@@ -15,7 +15,7 @@ module Aspera
15
15
 
16
16
  def detect(base_url)
17
17
  api = Rest.new(base_url: base_url)
18
- ping_result = api.read('ping')
18
+ ping_result = api.call(operation: 'GET', subpath: 'ping', headers: {'Accept' => 'application/json'})
19
19
  server_type = ping_result[:http]['Server']
20
20
  return nil unless ping_result[:data].is_a?(Hash) && ping_result[:data].empty?
21
21
  return nil unless server_type.is_a?(String) && server_type.include?('faspio')
@@ -65,7 +65,7 @@ module Aspera
65
65
  when :health
66
66
  nagios = Nagios.new
67
67
  begin
68
- result = api.read('ping')[:data]
68
+ result = api.read('ping')
69
69
  if result.is_a?(Hash) && result.empty?
70
70
  nagios.add_ok('api', 'answered ok')
71
71
  else
@@ -17,7 +17,7 @@ module Aspera
17
17
  api = Api::Httpgw.new(url: base_url)
18
18
  api_info = api.info
19
19
  return {
20
- url: base_url,
20
+ url: api.base_url,
21
21
  version: api_info['version']
22
22
  } if api_info.is_a?(Hash) && api_info.key?('download_endpoint')
23
23
  return nil