aspera-cli 4.23.0 → 4.24.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 (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +37 -1
  4. data/CONTRIBUTING.md +86 -29
  5. data/README.md +2109 -1300
  6. data/bin/ascli +2 -1
  7. data/bin/asession +4 -4
  8. data/lib/aspera/agent/base.rb +4 -0
  9. data/lib/aspera/agent/connect.rb +20 -18
  10. data/lib/aspera/agent/desktop.rb +14 -11
  11. data/lib/aspera/agent/direct.rb +39 -31
  12. data/lib/aspera/agent/httpgw.rb +2 -2
  13. data/lib/aspera/agent/node.rb +9 -11
  14. data/lib/aspera/agent/transferd.rb +18 -11
  15. data/lib/aspera/api/aoc.rb +44 -31
  16. data/lib/aspera/api/cos_node.rb +7 -5
  17. data/lib/aspera/api/httpgw.rb +15 -18
  18. data/lib/aspera/api/node.rb +104 -22
  19. data/lib/aspera/ascmd.rb +22 -16
  20. data/lib/aspera/ascp/installation.rb +37 -40
  21. data/lib/aspera/ascp/management.rb +5 -4
  22. data/lib/aspera/assert.rb +54 -23
  23. data/lib/aspera/cli/basic_auth_plugin.rb +8 -7
  24. data/lib/aspera/cli/error.rb +1 -1
  25. data/lib/aspera/cli/extended_value.rb +28 -29
  26. data/lib/aspera/cli/formatter.rb +191 -168
  27. data/lib/aspera/cli/hints.rb +29 -3
  28. data/lib/aspera/cli/main.rb +138 -107
  29. data/lib/aspera/cli/manager.rb +50 -30
  30. data/lib/aspera/cli/plugin.rb +148 -77
  31. data/lib/aspera/cli/plugin_factory.rb +2 -2
  32. data/lib/aspera/cli/plugins/aoc.rb +189 -70
  33. data/lib/aspera/cli/plugins/ats.rb +15 -13
  34. data/lib/aspera/cli/plugins/config.rb +100 -214
  35. data/lib/aspera/cli/plugins/console.rb +49 -18
  36. data/lib/aspera/cli/plugins/cos.rb +4 -4
  37. data/lib/aspera/cli/plugins/faspex.rb +45 -51
  38. data/lib/aspera/cli/plugins/faspex5.rb +164 -165
  39. data/lib/aspera/cli/plugins/faspio.rb +6 -5
  40. data/lib/aspera/cli/plugins/httpgw.rb +2 -2
  41. data/lib/aspera/cli/plugins/node.rb +144 -162
  42. data/lib/aspera/cli/plugins/orchestrator.rb +10 -14
  43. data/lib/aspera/cli/plugins/preview.rb +26 -29
  44. data/lib/aspera/cli/plugins/server.rb +28 -28
  45. data/lib/aspera/cli/plugins/shares.rb +40 -28
  46. data/lib/aspera/cli/sync_actions.rb +101 -80
  47. data/lib/aspera/cli/transfer_agent.rb +51 -50
  48. data/lib/aspera/cli/transfer_progress.rb +29 -20
  49. data/lib/aspera/cli/version.rb +1 -1
  50. data/lib/aspera/cli/wizard.rb +157 -0
  51. data/lib/aspera/colors.rb +13 -8
  52. data/lib/aspera/command_line_builder.rb +28 -22
  53. data/lib/aspera/command_line_converter.rb +31 -0
  54. data/lib/aspera/environment.rb +145 -101
  55. data/lib/aspera/faspex_gw.rb +1 -1
  56. data/lib/aspera/faspex_postproc.rb +3 -2
  57. data/lib/aspera/hash_ext.rb +1 -1
  58. data/lib/aspera/id_generator.rb +10 -10
  59. data/lib/aspera/keychain/base.rb +18 -0
  60. data/lib/aspera/keychain/encrypted_hash.rb +6 -12
  61. data/lib/aspera/keychain/factory.rb +9 -3
  62. data/lib/aspera/keychain/hashicorp_vault.rb +9 -6
  63. data/lib/aspera/keychain/macos_security.rb +13 -13
  64. data/lib/aspera/log.rb +91 -19
  65. data/lib/aspera/nagios.rb +5 -6
  66. data/lib/aspera/node_simulator.rb +12 -7
  67. data/lib/aspera/oauth/base.rb +5 -3
  68. data/lib/aspera/oauth/factory.rb +24 -18
  69. data/lib/aspera/oauth/jwt.rb +13 -1
  70. data/lib/aspera/oauth/url_json.rb +3 -3
  71. data/lib/aspera/oauth/web.rb +5 -3
  72. data/lib/aspera/persistency_folder.rb +2 -2
  73. data/lib/aspera/preview/file_types.rb +4 -3
  74. data/lib/aspera/preview/generator.rb +25 -12
  75. data/lib/aspera/preview/terminal.rb +10 -7
  76. data/lib/aspera/preview/utils.rb +11 -9
  77. data/lib/aspera/products/connect.rb +1 -1
  78. data/lib/aspera/products/desktop.rb +1 -1
  79. data/lib/aspera/products/other.rb +2 -2
  80. data/lib/aspera/products/transferd.rb +8 -6
  81. data/lib/aspera/proxy_auto_config.rb +1 -1
  82. data/lib/aspera/rest.rb +29 -22
  83. data/lib/aspera/rest_call_error.rb +1 -1
  84. data/lib/aspera/resumer.rb +1 -1
  85. data/lib/aspera/secret_hider.rb +46 -40
  86. data/lib/aspera/ssh.rb +13 -3
  87. data/lib/aspera/sync/args.schema.yaml +102 -0
  88. data/lib/aspera/sync/conf.schema.yaml +701 -0
  89. data/lib/aspera/sync/database.rb +83 -0
  90. data/lib/aspera/sync/operations.rb +296 -0
  91. data/lib/aspera/temp_file_manager.rb +3 -2
  92. data/lib/aspera/transfer/error.rb +1 -1
  93. data/lib/aspera/transfer/error_info.rb +1 -2
  94. data/lib/aspera/transfer/faux_file.rb +11 -10
  95. data/lib/aspera/transfer/parameters.rb +6 -5
  96. data/lib/aspera/transfer/spec.rb +15 -1
  97. data/lib/aspera/transfer/spec.schema.yaml +316 -293
  98. data/lib/aspera/transfer/spec_doc.rb +34 -16
  99. data/lib/aspera/transfer/uri.rb +5 -5
  100. data/lib/aspera/uri_reader.rb +14 -10
  101. data/lib/aspera/web_auth.rb +2 -2
  102. data/lib/aspera/web_server_simple.rb +2 -2
  103. data.tar.gz.sig +0 -0
  104. metadata +15 -13
  105. metadata.gz.sig +0 -0
  106. data/lib/aspera/transfer/async_conf.schema.yaml +0 -716
  107. data/lib/aspera/transfer/convert.rb +0 -29
  108. data/lib/aspera/transfer/sync.rb +0 -232
  109. data/lib/aspera/transfer/sync_instance.schema.yaml +0 -20
  110. data/lib/aspera/transfer/sync_session.schema.yaml +0 -86
@@ -35,13 +35,40 @@ module Aspera
35
35
  PATH_AUTH = 'auth'
36
36
  PATH_HEALTH = 'configuration/ping'
37
37
  PATH_API_DETECT = "#{PATH_API_V5}/#{PATH_HEALTH}"
38
- PER_PAGE_DEFAULT = 100
39
38
  # OAuth methods supported
40
39
  STD_AUTH_TYPES = %i[web jwt boot].freeze
41
40
  HEADER_ITERATION_TOKEN = 'X-Aspera-Next-Iteration-Token'
42
41
  HEADER_FASPEX_VERSION = 'X-IBM-Aspera'
43
- private_constant(*%i[JOB_RUNNING RECIPIENT_TYPES PACKAGE_TERMINATED PATH_HEALTH API_LIST_MAILBOX_TYPES PACKAGE_SEND_FROM_REMOTE_SOURCE PER_PAGE_DEFAULT
44
- STD_AUTH_TYPES HEADER_ITERATION_TOKEN HEADER_FASPEX_VERSION])
42
+ EMAIL_NOTIF_LIST = %w[
43
+ welcome_email
44
+ forgot_password
45
+ package_received
46
+ package_received_cc
47
+ package_sent_cc
48
+ package_downloaded
49
+ package_downloaded_cc
50
+ workgroup_package
51
+ upload_result
52
+ upload_result_cc
53
+ relay_started_cc
54
+ relay_finished_cc
55
+ relay_error_cc
56
+ shared_inbox_invitation
57
+ shared_inbox_submit
58
+ personal_invitation
59
+ personal_submit
60
+ account_approved
61
+ account_denied
62
+ package_file_processing_failed_sender
63
+ package_file_processing_failed_recipient
64
+ relay_failed_admin
65
+ relay_failed
66
+ admin_sync_failed
67
+ sync_failed
68
+ account_exist
69
+ mfa_code
70
+ ]
71
+ private_constant :JOB_RUNNING, :RECIPIENT_TYPES, :PACKAGE_TERMINATED, :PATH_HEALTH, :API_LIST_MAILBOX_TYPES, :PACKAGE_SEND_FROM_REMOTE_SOURCE, :STD_AUTH_TYPES, :HEADER_ITERATION_TOKEN, :HEADER_FASPEX_VERSION, :EMAIL_NOTIF_LIST
45
72
  class << self
46
73
  def application_name
47
74
  'Faspex'
@@ -71,7 +98,7 @@ module Aspera
71
98
  Log.log.debug{"detect error: #{e}"}
72
99
  end
73
100
  raise error if error
74
- return nil
101
+ return
75
102
  end
76
103
 
77
104
  # @param object [Plugin] An instance of this class
@@ -86,17 +113,18 @@ module Aspera
86
113
  raise "Username shall be an email in Faspex: #{wiz_username}" if !(wiz_username =~ /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i)
87
114
  if options.get_option(:client_id).nil? || options.get_option(:client_secret).nil?
88
115
  formatter.display_status('Ask the ascli client id and secret to your Administrator.'.red)
89
- formatter.display_status("Admin should login to: #{instance_url}")
116
+ formatter.display_status("Log in as an admin user at: #{instance_url}")
90
117
  Environment.instance.open_uri(instance_url)
91
118
  formatter.display_status('Navigate to: 𓃑 → Admin → Configurations → API clients')
92
119
  formatter.display_status('Create an API client with:')
93
120
  formatter.display_status('- name: ascli')
94
121
  formatter.display_status('- JWT: enabled')
95
- formatter.display_status("Then, logged in as #{wiz_username.red} go to your profile:")
96
- formatter.display_status('👤 → Account Settings → Preferences -> Public Key in PEM:')
122
+ formatter.display_status("Log in as user #{wiz_username.red}. Navigate to your profile:")
123
+ formatter.display_status('👤 → Account Settings → Preferences Public Key in PEM:')
97
124
  formatter.display_status(pub_key_pem)
98
125
  formatter.display_status('Once set, fill in the parameters:')
99
126
  end
127
+ return {preset_value: {}, test_args: ''} if options.get_option(:test_mode)
100
128
  return {
101
129
  preset_value: {
102
130
  url: instance_url,
@@ -116,7 +144,7 @@ module Aspera
116
144
  end
117
145
  end
118
146
 
119
- def initialize(**env)
147
+ def initialize(**_)
120
148
  super
121
149
  options.declare(:client_id, 'OAuth client identifier')
122
150
  options.declare(:client_secret, 'OAuth client secret')
@@ -140,10 +168,10 @@ module Aspera
140
168
  # resolve any redirect
141
169
  @faspex5_api_base_url = Rest.new(base_url: @faspex5_api_base_url, redirect_max: 3).call(operation: 'GET')[:http].uri.to_s
142
170
  encoded_context = Rest.query_to_h(URI.parse(@faspex5_api_base_url).query)['context']
143
- raise 'Bad faspex5 public link, missing context in query' if encoded_context.nil?
171
+ raise BadArgument, 'Bad faspex5 public link, missing context in query' if encoded_context.nil?
144
172
  # public link information (allowed usage)
145
173
  @pub_link_context = JSON.parse(Base64.decode64(encoded_context))
146
- Log.log.trace1{Log.dump(:@pub_link_context, @pub_link_context)}
174
+ Log.dump(:@pub_link_context, @pub_link_context, level: :trace1)
147
175
  # ok, we have the additional parameters, get the base url
148
176
  @faspex5_api_base_url = @faspex5_api_base_url.gsub(%r{/public/.*}, '').gsub(/\?.*/, '')
149
177
  @api_v5 = Rest.new(
@@ -166,7 +194,8 @@ module Aspera
166
194
  grant_method: :web,
167
195
  client_id: options.get_option(:client_id, mandatory: true),
168
196
  redirect_uri: options.get_option(:redirect_uri, mandatory: true)
169
- })
197
+ }
198
+ )
170
199
  when :jwt
171
200
  app_client_id = options.get_option(:client_id, mandatory: true)
172
201
  @api_v5 = Rest.new(
@@ -183,7 +212,8 @@ module Aspera
183
212
  },
184
213
  private_key_obj: OpenSSL::PKey::RSA.new(options.get_option(:private_key, mandatory: true), options.get_option(:passphrase)),
185
214
  headers: {typ: 'JWT'}
186
- })
215
+ }
216
+ )
187
217
  else Aspera.error_unexpected_value(auth_type)
188
218
  end
189
219
  # in case user wants to use HTTPGW tell transfer agent how to get address
@@ -223,7 +253,7 @@ module Aspera
223
253
  # user asked to not follow
224
254
  return status if status_list.nil?
225
255
  if status['upload_status'].eql?('submitted')
226
- config.progress_bar&.event(:pre_start, session_id: nil, info: status['upload_status'])
256
+ config.progress_bar&.event(:sessions_init, session_id: nil, info: status['upload_status'])
227
257
  elsif !total_sent
228
258
  config.progress_bar&.event(:session_start, session_id: id)
229
259
  config.progress_bar&.event(:session_size, session_id: id, info: status['bytes_total'].to_i)
@@ -232,7 +262,8 @@ module Aspera
232
262
  config.progress_bar&.event(:transfer, session_id: id, info: status['bytes_written'].to_i)
233
263
  end
234
264
  if status_list.include?(status['upload_status'])
235
- config.progress_bar&.event(:end, session_id: id)
265
+ config.progress_bar&.event(:session_end, session_id: id)
266
+ config.progress_bar&.event(:end)
236
267
  return status
237
268
  end
238
269
  sleep(1.0)
@@ -253,82 +284,25 @@ module Aspera
253
284
  return result
254
285
  end
255
286
 
256
- # Get a (full or partial) list of all entities of a given type with query: offset/limit
257
- # @param type [String] the type of entity to list (just a name)
258
- # @param query [Hash,nil] additional query parameters
259
- # @param real_path [String] real path if it's n ot just the type
260
- # @param item_list_key [String] key in the result to get the list of items
261
- def list_entities(type:, real_path: nil, item_list_key: nil, query: nil)
262
- Log.log.trace1{"list_entities t=#{type} p=#{real_path} k=#{item_list_key} q=#{query}"}
263
- type = type.to_s if type.is_a?(Symbol)
264
- query = {} if query.nil?
265
- Aspera.assert_type(type, String)
266
- Aspera.assert_type(query, Hash)
267
- item_list_key = type if item_list_key.nil?
268
- real_path = type if real_path.nil?
269
- result = []
270
- offset = 0
271
- max_items = query.delete(MAX_ITEMS)
272
- remain_pages = query.delete(MAX_PAGES)
273
- # merge default parameters, by default 100 per page
274
- query = {'limit'=> PER_PAGE_DEFAULT}.merge(query)
275
- loop do
276
- query['offset'] = offset
277
- page_result = @api_v5.read(real_path, query)
278
- Aspera.assert_type(page_result[item_list_key], Array)
279
- result.concat(page_result[item_list_key])
280
- # reach the limit set by user ?
281
- if !max_items.nil? && (result.length >= max_items)
282
- result = result.slice(0, max_items)
283
- break
284
- end
285
- break if result.length >= page_result['total_count']
286
- remain_pages -= 1 unless remain_pages.nil?
287
- break if remain_pages == 0
288
- offset += page_result[item_list_key].length
289
- formatter.long_operation_running
290
- end
291
- formatter.long_operation_terminated
292
- return result
293
- end
294
-
295
- # lookup an entity id from its name
296
- # @param type [String] the type of entity to lookup, by default it is the path, and it is also the field name in result
297
- # @param value [String] the value to lookup
298
- # @param field [String] the field to match, by default it is 'name'
299
- # @param real_path [String] real path if it's not just the type (override type)
300
- # @param item_list_key [String] key in the result to get the list of items (override type)
301
- # @param query [Hash] additional query parameters
302
- def lookup_entity_by_field(type:, value:, field: 'name', real_path: nil, item_list_key: nil, query: :default)
303
- if query.eql?(:default)
304
- Aspera.assert(field.eql?('name')){'Default query is on name only'}
305
- query = {'q'=> value}
306
- end
307
- found = list_entities(type: type, real_path: real_path, query: query, item_list_key: item_list_key).select{ |i| i[field].eql?(value)}
308
- case found.length
309
- when 0 then raise "No #{type} with #{field} = #{value}"
310
- when 1 then return found.first
311
- else raise "Found #{found.length} #{real_path} with #{field} = #{value}"
312
- end
313
- end
314
-
315
287
  # list all packages with optional filter
316
288
  def list_packages_with_filter(query: {})
317
289
  filter = options.get_next_argument('filter', mandatory: false, validation: Proc, default: ->(_x){true})
318
290
  # translate box name to API prefix (with ending slash)
319
291
  box = options.get_option(:box)
320
- real_path =
292
+ entity =
321
293
  case box
322
294
  when SpecialValues::ALL then 'packages' # only admin can list all packages globally
323
295
  when *API_LIST_MAILBOX_TYPES then "#{box}/packages"
324
296
  else
325
297
  group_type = options.get_option(:group_type)
326
- "#{group_type}/#{lookup_entity_by_field(type: group_type, value: box)['id']}/packages"
298
+ "#{group_type}/#{lookup_entity_by_field(api: @api_v5, entity: group_type, value: box)['id']}/packages"
327
299
  end
328
- return list_entities(
329
- type: 'packages',
330
- query: query_read_delete(default: query),
331
- real_path: real_path).select(&filter)
300
+ list, total = list_entities_limit_offset_total_count(
301
+ api: @api_v5,
302
+ entity: entity,
303
+ query: query_read_delete(default: query)
304
+ )
305
+ return list.select(&filter), total
332
306
  end
333
307
 
334
308
  def package_receive(package_ids)
@@ -344,22 +318,23 @@ module Aspera
344
318
  options.get_option(:url, mandatory: true),
345
319
  options.get_option(:username, mandatory: true),
346
320
  options.get_option(:box, mandatory: true)
347
- ]))
321
+ ])
322
+ )
348
323
  end
349
324
  packages = []
350
325
  case package_ids
351
326
  when SpecialValues::INIT
352
327
  Aspera.assert(skip_ids_persistency){'Only with option once_only'}
353
- skip_ids_persistency.data.clear.concat(list_packages_with_filter.map{ |p| p['id']})
328
+ skip_ids_persistency.data.clear.concat(list_packages_with_filter.first.map{ |p| p['id']})
354
329
  skip_ids_persistency.save
355
330
  return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
356
331
  when SpecialValues::ALL
357
332
  # TODO: if packages have same name, they will overwrite ?
358
- packages = list_packages_with_filter(query: {'status' => 'completed'})
359
- Log.log.trace1{Log.dump(:package_ids, packages.map{ |p| p['id']})}
360
- Log.log.trace1{Log.dump(:skip_ids, skip_ids_persistency.data)}
333
+ packages = list_packages_with_filter(query: {'status' => 'completed'}).first
334
+ Log.dump(:package_ids, level: :trace1){packages.map{ |p| p['id']}}
335
+ Log.dump(:skip_ids, skip_ids_persistency.data, level: :trace1)
361
336
  packages.reject!{ |p| skip_ids_persistency.data.include?(p['id'])} if skip_ids_persistency
362
- Log.log.trace1{Log.dump(:package_ids, packages.map{ |p| p['id']})}
337
+ Log.dump(:package_ids, level: :trace1){packages.map{ |p| p['id']}}
363
338
  else
364
339
  # a single id was provided, or a list of ids
365
340
  package_ids = [package_ids] unless package_ids.is_a?(Array)
@@ -384,7 +359,7 @@ module Aspera
384
359
  when /outbox/ then download_params[:type] = 'sent'
385
360
  when *API_LIST_MAILBOX_TYPES then nil # nothing to do
386
361
  else # shared inbox / workgroup
387
- download_params[:recipient_workgroup_id] = lookup_entity_by_field(type: options.get_option(:group_type), value: box)['id']
362
+ download_params[:recipient_workgroup_id] = lookup_entity_by_field(api: @api_v5, entity: options.get_option(:group_type), value: box)['id']
388
363
  end
389
364
  packages.each do |package|
390
365
  pkg_id = package['id']
@@ -448,17 +423,13 @@ module Aspera
448
423
  all_items = all_items.slice(0, max_items) if all_items.count > max_items
449
424
  break
450
425
  end
451
- if recursive
452
- folders_to_process.concat(response[:data]['items'].select{ |i| i['type'].eql?('directory')}.map{ |i| i['path']})
453
- end
426
+ folders_to_process.concat(response[:data]['items'].select{ |i| i['type'].eql?('directory')}.map{ |i| i['path']}) if recursive
454
427
  if use_paging
455
428
  iteration_token = response[:http][HEADER_ITERATION_TOKEN]
456
429
  break if iteration_token.nil? || iteration_token.empty?
457
430
  query['iteration_token'] = iteration_token
458
431
  else
459
- if total_count.nil?
460
- total_count = response[:data]['total_count']
461
- end
432
+ total_count = response[:data]['total_count'] if total_count.nil?
462
433
  break if response[:data]['item_count'].eql?(0)
463
434
  query['offset'] += response[:data]['item_count']
464
435
  end
@@ -484,7 +455,7 @@ module Aspera
484
455
  location = case options.get_option(:box)
485
456
  when 'inbox' then 'received'
486
457
  when 'outbox' then 'sent'
487
- else raise 'Browse only available for inbox and outbox'
458
+ else raise BadArgument, 'Browse only available for inbox and outbox'
488
459
  end
489
460
  return browse_folder("packages/#{package_id}/files/#{location}")
490
461
  when :status
@@ -536,9 +507,11 @@ module Aspera
536
507
  # send from remote shared folder
537
508
  if (m = shared_folder.match(REGEX_LOOKUP_ID_BY_FIELD))
538
509
  shared_folder = lookup_entity_by_field(
539
- type: 'shared_folders',
510
+ api: @api_v5,
511
+ entity: 'shared_folders',
540
512
  field: m[1],
541
- value: ExtendedValue.instance.evaluate(m[2]))['id']
513
+ value: ExtendedValue.instance.evaluate(m[2])
514
+ )['id']
542
515
  end
543
516
  transfer_request = {shared_folder_id: shared_folder, paths: transfer.source_list}
544
517
  # start remote transfer and get first status
@@ -551,100 +524,102 @@ module Aspera
551
524
  return Main.result_single_object(result)
552
525
  end
553
526
  when :list
554
- return {
555
- type: :object_list,
556
- data: list_packages_with_filter,
557
- fields: %w[id title release_date total_bytes total_files created_time state]
558
- }
527
+ list, total = list_packages_with_filter
528
+ return Main.result_object_list(list, total: total, fields: %w[id title release_date total_bytes total_files created_time state])
559
529
  end
560
530
  end
561
531
 
562
- def execute_resource(res_type)
563
- list_key = res_path = res_type.to_s
564
- id_as_arg = false
565
- display_fields = nil
566
- adm_api = @api_v5
532
+ def execute_resource(res_sym)
533
+ exec_args = {
534
+ api: @api_v5,
535
+ entity: res_sym.to_s,
536
+ tclo: true
537
+ }
567
538
  res_id_query = :default
568
- delete_style = nil
569
- available_commands = [].concat(Plugin::ALL_OPS)
570
- case res_type
539
+ available_commands = Plugin::ALL_OPS
540
+ case res_sym
571
541
  when :metadata_profiles
572
- res_path = 'configuration/metadata_profiles'
573
- list_key = 'profiles'
542
+ exec_args[:entity] = 'configuration/metadata_profiles'
543
+ exec_args[:items_key] = 'profiles'
574
544
  when :alternate_addresses
575
- res_path = 'configuration/alternate_addresses'
545
+ exec_args[:entity] = 'configuration/alternate_addresses'
576
546
  when :distribution_lists
577
- res_path = 'account/distribution_lists'
578
- list_key = 'distribution_lists'
579
- delete_style = 'ids'
547
+ exec_args[:entity] = 'account/distribution_lists'
548
+ exec_args[:delete_style] = 'ids'
580
549
  when :email_notifications
581
- list_key = false
582
- id_as_arg = 'type'
550
+ exec_args.delete(:items_key)
551
+ exec_args[:id_as_arg] = 'type'
583
552
  when :accounts
584
- display_fields = Formatter.all_but('user_profile_data_attributes')
585
- available_commands.push(:reset_password)
553
+ exec_args[:display_fields] = Formatter.all_but('user_profile_data_attributes')
554
+ available_commands += [:reset_password]
586
555
  when :oauth_clients
587
- display_fields = Formatter.all_but('public_key')
588
- adm_api = Rest.new(**@api_v5.params, base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}")
556
+ exec_args[:display_fields] = Formatter.all_but('public_key')
557
+ exec_args[:api] = Rest.new(**@api_v5.params, base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}")
558
+ exec_args[:list_query] = {'expand': true, 'no_api_path': true, 'client_types[]': 'public'}
589
559
  when :shared_inboxes, :workgroups
590
- available_commands.push(:members, :saml_groups, :invite_external_collaborator)
560
+ available_commands += %i[members saml_groups invite_external_collaborator]
591
561
  res_id_query = {'all': true}
592
562
  when :nodes
593
- available_commands.push(:shared_folders, :browse)
563
+ available_commands += %i[shared_folders browse]
594
564
  end
595
565
  res_command = options.get_next_command(available_commands)
566
+ return Main.result_value_list(EMAIL_NOTIF_LIST, name: 'email_id') if res_command.eql?(:list) && res_sym.eql?(:email_notifications)
596
567
  case res_command
597
568
  when *Plugin::ALL_OPS
598
- return entity_command(
599
- res_command, adm_api, res_path, item_list_key: list_key, display_fields: display_fields, id_as_arg: id_as_arg,
600
- delete_style: delete_style) do |field, value|
601
- lookup_entity_by_field(
602
- type: res_type, value: value, field: field, real_path: res_path, item_list_key: list_key, query: res_id_query)['id']
569
+ return entity_execute(command: res_command, **exec_args) do |field, value|
570
+ lookup_entity_by_field(api: @api_v5, entity: exec_args[:entity], value: value, field: field, items_key: exec_args[:items_key], query: res_id_query)['id']
603
571
  end
604
572
  when :shared_folders
573
+ # nodes
605
574
  node_id = instance_identifier do |field, value|
606
- lookup_entity_by_field(type: res_type, field: field, value: value)['id']
575
+ lookup_entity_by_field(api: @api_v5, entity: 'nodes', field: field, value: value)['id']
607
576
  end
608
- sh_path = "#{res_path}/#{node_id}/shared_folders"
609
- sh_command = options.get_next_command([:user].concat(Plugin::ALL_OPS))
577
+ shfld_entity = "nodes/#{node_id}/shared_folders"
578
+ sh_command = options.get_next_command(Plugin::ALL_OPS + [:user])
610
579
  case sh_command
611
580
  when *Plugin::ALL_OPS
612
- return entity_command(sh_command, adm_api, sh_path, item_list_key: 'shared_folders') do |field, value|
613
- lookup_entity_by_field(type: 'shared_folders', real_path: sh_path, field: field, value: value)['id']
581
+ return entity_execute(
582
+ api: @api_v5,
583
+ entity: shfld_entity,
584
+ command: sh_command
585
+ ) do |field, value|
586
+ lookup_entity_by_field(api: @api_v5, entity: shfld_entity, field: field, value: value)['id']
614
587
  end
615
588
  when :user
616
589
  sh_id = instance_identifier do |field, value|
617
- lookup_entity_by_field(type: 'shared_folders', real_path: sh_path, field: field, value: value)['id']
590
+ lookup_entity_by_field(api: @api_v5, entity: shfld_entity, field: field, value: value)['id']
618
591
  end
619
- user_path = "#{sh_path}/#{sh_id}/custom_access_users"
620
- return entity_action(adm_api, user_path, item_list_key: 'users') do |field, value|
621
- lookup_entity_by_field(type: 'users', real_path: user_path, field: field, value: value)['id']
592
+ user_path = "#{shfld_entity}/#{sh_id}/custom_access_users"
593
+ return entity_execute(api: @api_v5, entity: user_path, items_key: 'users') do |field, value|
594
+ lookup_entity_by_field(api: @api_v5, entity: user_path, items_key: 'users', field: field, value: value)['id']
622
595
  end
623
596
 
624
597
  end
625
598
  when :browse
599
+ # nodes
626
600
  node_id = instance_identifier do |field, value|
627
- lookup_entity_by_field(
628
- type: res_type, value: value, field: field, real_path: res_path, item_list_key: list_key, query: res_id_query)['id']
601
+ lookup_entity_by_field(api: @api_v5, entity: 'nodes', value: value, field: field)['id']
629
602
  end
630
- return browse_folder("#{res_path}/#{node_id}/browse")
603
+ return browse_folder("nodes/#{node_id}/browse")
631
604
  when :invite_external_collaborator
632
- shared_inbox_id = instance_identifier{ |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value, query: res_id_query)['id']}
605
+ # :shared_inboxes, :workgroups
606
+ shared_inbox_id = instance_identifier{ |field, value| lookup_entity_by_field(api: @api_v5, entity: res_sym.to_s, field: field, value: value, query: res_id_query)['id']}
633
607
  creation_payload = value_create_modify(command: res_command, type: [Hash, String])
634
608
  creation_payload = {'email_address' => creation_payload} if creation_payload.is_a?(String)
635
- res_path = "#{res_type}/#{shared_inbox_id}/external_collaborator"
636
- result = adm_api.create(res_path, creation_payload)
609
+ result = @api_v5.create("#{res_sym}/#{shared_inbox_id}/external_collaborator", creation_payload)
637
610
  formatter.display_status(result['message'])
638
611
  result = lookup_entity_by_field(
639
- type: 'members',
640
- real_path: "#{res_type}/#{shared_inbox_id}/members",
612
+ api: @api_v5,
613
+ entity: "#{res_sym}/#{shared_inbox_id}/members",
614
+ items_key: 'members',
641
615
  value: creation_payload['email_address'],
642
- query: {})
616
+ query: {}
617
+ )
643
618
  return Main.result_single_object(result)
644
619
  when :members, :saml_groups
645
- res_id = instance_identifier{ |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value, query: res_id_query)['id']}
646
- res_prefix = "#{res_type}/#{res_id}"
647
- res_path = "#{res_prefix}/#{res_command}"
620
+ # :shared_inboxes, :workgroups
621
+ res_id = instance_identifier{ |field, value| lookup_entity_by_field(api: @api_v5, entity: res_sym.to_s, field: field, value: value, query: res_id_query)['id']}
622
+ res_path = "#{res_sym}/#{res_id}/#{res_command}"
648
623
  list_key = res_command.to_s
649
624
  list_key = 'groups' if res_command.eql?(:saml_groups)
650
625
  sub_command = options.get_next_command(%i[create list modify delete])
@@ -655,10 +630,12 @@ module Aspera
655
630
  users = users.map do |user|
656
631
  if (m = user.match(REGEX_LOOKUP_ID_BY_FIELD))
657
632
  lookup_entity_by_field(
658
- type: 'accounts',
633
+ api: @api_v5,
634
+ entity: 'accounts',
659
635
  field: m[1],
660
636
  value: ExtendedValue.instance.evaluate(m[2]),
661
- query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})})['id']
637
+ query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})}
638
+ )['id']
662
639
  else
663
640
  # it's the user id (not member id...)
664
641
  user
@@ -667,16 +644,24 @@ module Aspera
667
644
  access = options.get_next_argument('level', mandatory: false, accept_list: %i[submit_only standard shared_inbox_admin], default: :standard)
668
645
  options.unshift_next_argument({user: users.map{ |u| {id: u, access: access}}})
669
646
  end
670
- return entity_command(sub_command, adm_api, res_path, item_list_key: list_key) do |field, value|
647
+ return entity_execute(
648
+ api: @api_v5,
649
+ entity: res_path,
650
+ command: sub_command,
651
+ items_key: list_key
652
+ ) do |field, value|
671
653
  lookup_entity_by_field(
672
- type: 'accounts',
654
+ api: @api_v5,
655
+ entity: 'accounts',
673
656
  field: field,
674
657
  value: value,
675
- query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})})['id']
658
+ query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})}
659
+ )['id']
676
660
  end
677
661
  when :reset_password
678
- contact_id = instance_identifier{ |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value, query: res_id_query)['id']}
679
- adm_api.create("#{res_type}/#{contact_id}/reset_password", {})
662
+ # :accounts
663
+ contact_id = instance_identifier{ |field, value| lookup_entity_by_field(api: @api_v5, entity: 'accounts', field: field, value: value, query: res_id_query)['id']}
664
+ @api_v5.create("accounts/#{contact_id}/reset_password", {})
680
665
  return Main.result_status('password reset, user shall check email')
681
666
  end
682
667
  Aspera.error_unreachable_line
@@ -700,12 +685,21 @@ module Aspera
700
685
  event_type = options.get_next_command(%i[application webhook])
701
686
  case event_type
702
687
  when :application
703
- return Main.result_object_list(
704
- list_entities(type: 'application_events', query: query_read_delete),
705
- fields: %w[event_type created_at application user.name])
688
+ list, total = list_entities_limit_offset_total_count(
689
+ api: @api_v5,
690
+ entity: 'application_events',
691
+ query: query_read_delete
692
+ )
693
+
694
+ return Main.result_object_list(list, total: total, fields: %w[event_type created_at application user.name])
706
695
  when :webhook
707
- return Main.result_object_list(
708
- list_entities(type: 'all_webhooks_events', query: query_read_delete, item_list_key: 'events'))
696
+ list, total = list_entities_limit_offset_total_count(
697
+ api: @api_v5,
698
+ entity: 'all_webhooks_events',
699
+ query: query_read_delete,
700
+ items_key: 'events'
701
+ )
702
+ return Main.result_object_list(list, total: total)
709
703
  end
710
704
  when :configuration
711
705
  conf_path = 'configuration'
@@ -717,6 +711,7 @@ module Aspera
717
711
  return Main.result_single_object(@api_v5.update(conf_path, value_create_modify(command: conf_cmd)))
718
712
  end
719
713
  when :smtp
714
+ # only one SMTP config
720
715
  smtp_path = 'configuration/smtp'
721
716
  smtp_cmd = options.get_next_command(%i[show create modify delete test])
722
717
  case smtp_cmd
@@ -807,11 +802,15 @@ module Aspera
807
802
  @api_v5.create("#{invitation_endpoint}/#{instance_identifier}/resend")
808
803
  return Main.result_status('Invitation resent')
809
804
  else
810
- return entity_command(
811
- invitation_command, @api_v5, invitation_endpoint, item_list_key: invitation_endpoint,
812
- display_fields: %w[id public recipient_type recipient_name email_address]) do |field, value|
813
- lookup_entity_by_field(type: invitation_endpoint, field: field, value: value, query: {})['id']
814
- end
805
+ return entity_execute(
806
+ api: @api_v5,
807
+ entity: invitation_endpoint,
808
+ command: invitation_command,
809
+ items_key: invitation_endpoint,
810
+ display_fields: %w[id public recipient_type recipient_name email_address]
811
+ ) do |field, value|
812
+ lookup_entity_by_field(api: @api_v5, entity: invitation_endpoint, field: field, value: value, query: {})['id']
813
+ end
815
814
  end
816
815
  when :gateway
817
816
  require 'aspera/faspex_gw'
@@ -17,8 +17,8 @@ module Aspera
17
17
  api = Rest.new(base_url: base_url)
18
18
  ping_result = api.call(operation: 'GET', subpath: 'ping', headers: {'Accept' => Rest::MIME_JSON})
19
19
  server_type = ping_result[:http]['Server']
20
- return nil unless ping_result[:data].is_a?(Hash) && ping_result[:data].empty?
21
- return nil unless server_type.is_a?(String) && server_type.include?('faspio')
20
+ return unless ping_result[:data].is_a?(Hash) && ping_result[:data].empty?
21
+ return unless server_type.is_a?(String) && server_type.include?('faspio')
22
22
  return {
23
23
  version: server_type.gsub(%r{^.*/}, ''),
24
24
  url: base_url
@@ -39,7 +39,7 @@ module Aspera
39
39
  end
40
40
  ACTIONS = %i[health bridges].freeze
41
41
 
42
- def initialize(**env)
42
+ def initialize(**_)
43
43
  super
44
44
  options.declare(:auth, 'OAuth type of authentication', values: %i[jwt basic])
45
45
  options.declare(:client_id, 'OAuth client identifier')
@@ -70,7 +70,8 @@ module Aspera
70
70
  },
71
71
  private_key_obj: OpenSSL::PKey::RSA.new(options.get_option(:private_key, mandatory: true), options.get_option(:passphrase)),
72
72
  headers: {typ: 'JWT'}
73
- })
73
+ }
74
+ )
74
75
  end
75
76
  command = options.get_next_command(ACTIONS)
76
77
  case command
@@ -88,7 +89,7 @@ module Aspera
88
89
  end
89
90
  return nagios.result
90
91
  when :bridges
91
- return entity_action(api, 'bridges')
92
+ return entity_execute(api: api, entity: 'bridges')
92
93
  end
93
94
  end
94
95
  end
@@ -20,7 +20,7 @@ module Aspera
20
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
- return nil
23
+ return
24
24
  end
25
25
 
26
26
  # @param object [Plugin] An instance of this class
@@ -37,7 +37,7 @@ module Aspera
37
37
  end
38
38
  ACTIONS = %i[health info].freeze
39
39
 
40
- def initialize(**env)
40
+ def initialize(**_)
41
41
  super
42
42
  options.declare(:url, 'URL of application, e.g. https://app.example.com/aspera/app')
43
43
  options.parse_options!