aspera-cli 4.25.6 → 4.26.0

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 (40) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +74 -47
  4. data/CONTRIBUTING.md +1 -1
  5. data/lib/aspera/api/aoc.rb +118 -78
  6. data/lib/aspera/api/node.rb +101 -49
  7. data/lib/aspera/ascp/installation.rb +94 -30
  8. data/lib/aspera/cli/extended_value.rb +1 -0
  9. data/lib/aspera/cli/formatter.rb +47 -40
  10. data/lib/aspera/cli/manager.rb +30 -4
  11. data/lib/aspera/cli/plugins/aoc.rb +214 -136
  12. data/lib/aspera/cli/plugins/ats.rb +3 -3
  13. data/lib/aspera/cli/plugins/base.rb +17 -42
  14. data/lib/aspera/cli/plugins/config.rb +5 -3
  15. data/lib/aspera/cli/plugins/console.rb +3 -3
  16. data/lib/aspera/cli/plugins/faspex.rb +5 -5
  17. data/lib/aspera/cli/plugins/faspex5.rb +20 -18
  18. data/lib/aspera/cli/plugins/node.rb +66 -70
  19. data/lib/aspera/cli/plugins/oauth.rb +5 -12
  20. data/lib/aspera/cli/plugins/orchestrator.rb +13 -13
  21. data/lib/aspera/cli/plugins/preview.rb +116 -80
  22. data/lib/aspera/cli/plugins/server.rb +2 -10
  23. data/lib/aspera/cli/plugins/shares.rb +7 -7
  24. data/lib/aspera/cli/version.rb +1 -1
  25. data/lib/aspera/dot_container.rb +7 -3
  26. data/lib/aspera/environment.rb +3 -2
  27. data/lib/aspera/log.rb +1 -1
  28. data/lib/aspera/preview/file_types.rb +1 -1
  29. data/lib/aspera/preview/generator.rb +146 -91
  30. data/lib/aspera/preview/options.rb +4 -1
  31. data/lib/aspera/preview/terminal.rb +50 -20
  32. data/lib/aspera/preview/utils.rb +76 -34
  33. data/lib/aspera/products/transferd.rb +1 -1
  34. data/lib/aspera/rest.rb +1 -0
  35. data/lib/aspera/rest_list.rb +23 -16
  36. data/lib/aspera/secret_hider.rb +3 -1
  37. data/lib/aspera/uri_reader.rb +17 -2
  38. data.tar.gz.sig +0 -0
  39. metadata +5 -5
  40. metadata.gz.sig +0 -0
@@ -24,26 +24,25 @@ module Aspera
24
24
  REDIRECT_LOCALHOST = 'http://localhost:12345'
25
25
  # admin objects that can be manipulated
26
26
  ADMIN_OBJECTS = %i[
27
- self
28
- organization
29
- user
30
- group
31
- group_membership
32
27
  client
28
+ client_access_key
29
+ client_registration_token
33
30
  contact
34
31
  dropbox
32
+ dropbox_membership
33
+ group
34
+ group_membership
35
+ kms_profile
35
36
  node
36
37
  operation
38
+ organization
37
39
  package
38
40
  saml_configuration
41
+ self
42
+ short_link
43
+ user
39
44
  workspace
40
45
  workspace_membership
41
- dropbox_membership
42
- short_link
43
- application
44
- client_registration_token
45
- client_access_key
46
- kms_profile
47
46
  ].freeze
48
47
  # query to list fully received packages
49
48
  PACKAGE_RECEIVED_BASE_QUERY = {
@@ -53,10 +52,8 @@ module Aspera
53
52
  'completed' => true
54
53
  }.freeze
55
54
  PACKAGE_LIST_DEFAULT_FIELDS = %w[id name created_at files_completed bytes_transferred].freeze
56
- # options and parameters for Api::AoC.new
57
- OPTIONS_NEW = %i[url auth client_id client_secret scope redirect_uri private_key passphrase username password workspace].freeze
58
55
 
59
- private_constant :REDIRECT_LOCALHOST, :ADMIN_OBJECTS, :PACKAGE_RECEIVED_BASE_QUERY, :OPTIONS_NEW, :PACKAGE_LIST_DEFAULT_FIELDS
56
+ private_constant :REDIRECT_LOCALHOST, :ADMIN_OBJECTS, :PACKAGE_RECEIVED_BASE_QUERY, :PACKAGE_LIST_DEFAULT_FIELDS
60
57
  class << self
61
58
  def application_name
62
59
  'Aspera on Cloud'
@@ -220,21 +217,36 @@ module Aspera
220
217
  # Change API scope for subsequent calls, re-instantiate API object
221
218
  # @param new_scope [String] New scope
222
219
  def change_api_scope(new_scope)
220
+ # Discard cache
223
221
  @cache_api_aoc = nil
224
222
  @scope = new_scope
223
+ nil
225
224
  end
226
225
 
227
226
  # Create an API object with the options from CLI, but with a different subpath
228
- # @param aoc_base_path [String] New subpath
227
+ # @param base_path [String] Base path for APIs.
229
228
  # @return [Api::AoC] API object for AoC (is Rest)
230
- def api_from_options(aoc_base_path)
231
- return Api::AoC.new(**Oauth.args_from_options(
232
- options,
233
- defaults: {workspace: nil},
229
+ def api_from_options(base_path)
230
+ # Get all existing OAuth kwargs from `options`.
231
+ api = Api::AoC.new(
234
232
  scope: @scope,
235
- subpath: aoc_base_path,
236
- secret_finder: config
237
- ))
233
+ subpath: base_path,
234
+ secret_finder: config,
235
+ **Oauth.kwargs_from_options(options)
236
+ )
237
+ # User set a workspace ?
238
+ # @type [String, nil]
239
+ workspace = options.get_option(:workspace)
240
+ if !workspace.nil? && (m = Manager.percent_selector(workspace))
241
+ case m[:field]
242
+ when 'name' then api.ws_ids[:name] = m[:value]
243
+ when 'id' then api.ws_ids[:id] = m[:value]
244
+ else Aspera.error_unexpected_value(m[:field]){'workspace selector: only `name` or `id`'}
245
+ end
246
+ else
247
+ api.ws_ids[:name] = workspace
248
+ end
249
+ api
238
250
  end
239
251
 
240
252
  # AoC Rest object
@@ -260,7 +272,7 @@ module Aspera
260
272
  # * `workspace_name` [String] (optional) the name, included if +name+ is true.
261
273
  # @note The key type (String or Symbol) depends on the +string+ parameter.
262
274
  def workspace_id_hash(hash = nil, string: false, name: false)
263
- info = aoc_api.workspace
275
+ info = aoc_api.workspace_info
264
276
  hash = {} if hash.nil?
265
277
  fields = %i[id]
266
278
  fields.push(:name) if name
@@ -276,9 +288,9 @@ module Aspera
276
288
  # @param resource_class_path url path for resource
277
289
  # @return identifier
278
290
  def get_resource_id_from_args(resource_class_path)
279
- return instance_identifier do |field, value|
291
+ return options.instance_identifier do |field, value|
280
292
  Aspera.assert(field.eql?('name'), type: BadArgument){'only selection by name is supported'}
281
- aoc_api.lookup_by_name(resource_class_path, value)['id']
293
+ aoc_api.lookup_with_q(resource_class_path, value: value)['id']
282
294
  end
283
295
  end
284
296
 
@@ -309,7 +321,7 @@ module Aspera
309
321
  # convenience: specify name instead of id
310
322
  raise BadArgument, 'Use field dropbox_name or dropbox_id, not both' if query.key?('dropbox_id')
311
323
  # TODO : craft a query that looks for dropbox only in current workspace
312
- query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query.delete('dropbox_name'))['id']
324
+ query['dropbox_id'] = aoc_api.lookup_with_q('dropboxes', value: query.delete('dropbox_name'))['id']
313
325
  end
314
326
  workspace_id_hash(query, string: true)
315
327
  # by default show dropbox packages only for dropboxes
@@ -327,11 +339,10 @@ module Aspera
327
339
  return aoc_api.read_with_paging('packages', query.compact)
328
340
  end
329
341
 
330
- NODE4_EXT_COMMANDS = %i[transfer].concat(Node::COMMANDS_GEN4).freeze
331
- private_constant :NODE4_EXT_COMMANDS
342
+ FILES_COMMANDS = (Node::COMMANDS_GEN4 + %i[transfer]).freeze
332
343
 
333
- # Execute a node gen4 command
334
- # @param command_repo [Symbol] command to execute
344
+ # Execute a node gen4 command starting at given node and file IDs
345
+ # @param command_repo [Symbol] Command to execute
335
346
  # @param node_id [String] Node identifier
336
347
  # @param file_id [String] Root file id for the operation (can be AK root, or other, e.g. package, or link). If `nil` use AK root file id.
337
348
  # @param scope [String] node scope (Node::SCOPE_<USER|ADMIN>), or nil (requires secret)
@@ -341,7 +352,7 @@ module Aspera
341
352
  scope: scope,
342
353
  **workspace_id_hash(name: true)
343
354
  )
344
- file_id = top_node_api.read("access_keys/#{top_node_api.app_info[:node_info]['access_key']}")['root_file_id'] if file_id.nil?
355
+ file_id = top_node_api.read("access_keys/#{top_node_api.app_info.node_info['access_key']}")['root_file_id'] if file_id.nil?
345
356
  node_plugin = Node.new(context: context, api: top_node_api)
346
357
  case command_repo
347
358
  when *Node::COMMANDS_GEN4
@@ -363,23 +374,23 @@ module Aspera
363
374
  server_folder = source_folder
364
375
  else Aspera.error_unreachable_line
365
376
  end
366
- client_apfid = top_node_api.resolve_api_fid(file_id, client_folder)
367
- server_apfid = top_node_api.resolve_api_fid(file_id, server_folder)
377
+ client_apifid = top_node_api.resolve_api_fid(file_id, client_folder)
378
+ server_apifid = top_node_api.resolve_api_fid(file_id, server_folder)
368
379
  # force node as transfer agent
369
380
  transfer.agent_instance = Agent::Node.new(
370
- url: client_apfid[:api].base_url,
371
- username: client_apfid[:api].app_info[:node_info]['access_key'],
372
- password: client_apfid[:api].oauth.authorization,
373
- root_id: client_apfid[:file_id]
381
+ url: client_apifid.node_api.base_url,
382
+ username: client_apifid.node_api.app_info.node_info['access_key'],
383
+ password: client_apifid.node_api.oauth.authorization,
384
+ root_id: client_apifid.file_id
374
385
  )
375
386
  # additional node to node TS info
376
387
  add_ts = {
377
- 'remote_access_key' => server_apfid[:api].app_info[:node_info]['access_key'],
378
- 'destination_root_id' => server_apfid[:file_id],
379
- 'source_root_id' => client_apfid[:file_id]
388
+ 'remote_access_key' => server_apifid.node_api.app_info.node_info['access_key'],
389
+ 'destination_root_id' => server_apifid.file_id,
390
+ 'source_root_id' => client_apifid.file_id
380
391
  }
381
- return Main.result_transfer(transfer.start(server_apfid[:api].transfer_spec_gen4(
382
- server_apfid[:file_id],
392
+ return Main.result_transfer(transfer.start(server_apifid.node_api.transfer_spec_gen4(
393
+ server_apifid.file_id,
383
394
  client_direction,
384
395
  add_ts
385
396
  )))
@@ -388,68 +399,72 @@ module Aspera
388
399
  Aspera.error_unreachable_line
389
400
  end
390
401
 
402
+ # Execute an action on admin resources
391
403
  # @param resource_type [Symbol] One of ADMIN_OBJECTS
392
404
  def execute_resource_action(resource_type)
393
- # get path on API, resource type is singular, but api is plural
394
- resource_class_path =
395
- case resource_type
396
- # special cases: singleton, in admin, with x
397
- when :self, :organization then resource_type
398
- when :client_registration_token, :client_access_key then "admin/#{resource_type}s"
399
- when :application then 'admin/apps_new'
400
- when :dropbox then "#{resource_type}es"
401
- when :kms_profile then "integrations/#{resource_type}s"
402
- else "#{resource_type}s"
403
- end
404
- # build list of supported operations
405
- singleton_object = %i[self organization].include?(resource_type)
406
- global_operations = %i[create list]
407
- supported_operations = %i[show modify]
408
- supported_operations.push(:delete, *global_operations) unless singleton_object
409
- supported_operations.push(:do, :bearer_token) if resource_type.eql?(:node)
410
- supported_operations.push(:set_pub_key) if resource_type.eql?(:client)
411
- supported_operations.push(:shared_folder, :dropbox) if resource_type.eql?(:workspace)
405
+ require_workspace_id = false
406
+ list_default_fields = %w[id name]
407
+ list_default_query = {}
408
+ supported_operations = Operations::ALL
409
+ resource_class_path = "#{resource_type}s"
410
+ case resource_type
411
+ when :client
412
+ supported_operations += %i[set_pub_key]
413
+ when :client_access_key
414
+ resource_class_path = "admin/#{resource_type}s"
415
+ when :client_registration_token
416
+ resource_class_path = "admin/#{resource_type}s"
417
+ list_default_fields = %w[id value data.client_subject_scopes created_at]
418
+ when :contact
419
+ list_default_fields = %w[source_type source_id name email]
420
+ # list_default_query = {'include_only_user_personal_contacts' => true} if @scope == Api::AoC::Scope::USER
421
+ when :dropbox
422
+ require_workspace_id = true
423
+ resource_class_path = "#{resource_type}es"
424
+ when :group_membership
425
+ list_default_fields = %w[id group_id member_type member_id]
426
+ when :kms_profile
427
+ resource_class_path = "integrations/#{resource_type}s"
428
+ when :node
429
+ list_default_fields = %w[id name host access_key]
430
+ supported_operations += %i[do bearer_token]
431
+ when :operation
432
+ list_default_fields = nil
433
+ when :organization, :self
434
+ supported_operations = Operations::SINGLETON
435
+ resource_instance_path = resource_class_path = resource_type
436
+ when :short_link
437
+ list_default_fields = %w[id short_url data.url_token_data.purpose password_enabled password_protected updated_by_user_id updated_at]
438
+ when :user
439
+ list_default_fields = %w[id name email]
440
+ supported_operations += %i[preferences notifications]
441
+ when :workspace
442
+ supported_operations += %i[shared_folder dropbox]
443
+ when :workspace_membership
444
+ list_default_fields = %w[id workspace_id member_type member_id]
445
+ end
412
446
  command = options.get_next_command(supported_operations)
413
- # require identifier for non global commands
414
- if !singleton_object && !global_operations.include?(command)
447
+ # Require identifier for non global commands
448
+ if (supported_operations != Operations::SINGLETON) && !Operations::GLOBAL.include?(command)
415
449
  res_id = get_resource_id_from_args(resource_class_path)
416
450
  resource_instance_path = "#{resource_class_path}/#{res_id}"
417
451
  end
418
- resource_instance_path = resource_class_path if singleton_object
419
452
  case command
420
453
  when :create
421
454
  id_result = 'id'
422
455
  id_result = 'token' if resource_class_path.eql?('admin/client_registration_tokens')
423
456
  # TODO: report inconsistency: creation url is !=, and does not return id.
424
457
  resource_class_path = 'admin/client_registration/token' if resource_class_path.eql?('admin/client_registration_tokens')
458
+ workspace_id = aoc_api.workspace_info[:id] if require_workspace_id
425
459
  return do_bulk_operation(command: command, descr: 'creation data', id_result: id_result) do |params|
460
+ params['workspace_id'] = workspace_id if require_workspace_id && workspace_id && !params.key?('workspace_id')
426
461
  aoc_api.create(resource_class_path, params)
427
462
  end
428
463
  when :list
429
- default_fields = ['id']
430
- default_query = {}
431
- case resource_type
432
- when :application
433
- default_query = {organization_apps: true}
434
- default_fields.push('app_type', 'app_name', 'available', 'direct_authorizations_allowed', 'workspace_authorizations_allowed')
435
- when :client, :client_access_key, :dropbox, :group, :package, :saml_configuration, :workspace then default_fields.push('name')
436
- when :client_registration_token then default_fields.push('value', 'data.client_subject_scopes', 'created_at')
437
- when :contact
438
- default_fields = %w[source_type source_id name email]
439
- default_query = {'include_only_user_personal_contacts' => true} if @scope == Api::AoC::Scope::USER
440
- when :node then default_fields.push('name', 'host', 'access_key')
441
- when :operation then default_fields = nil
442
- when :short_link then default_fields.push('short_url', 'data.url_token_data.purpose')
443
- when :user then default_fields.push('name', 'email')
444
- when :group_membership then default_fields.push('group_id', 'member_type', 'member_id')
445
- when :workspace_membership then default_fields.push('workspace_id', 'member_type', 'member_id')
446
- end
447
- return result_list(resource_class_path, fields: default_fields, default_query: default_query)
464
+ return result_list(resource_class_path, fields: list_default_fields, default_query: list_default_query)
448
465
  when :show
449
- object = aoc_api.read(resource_instance_path)
450
- # default: show all, but certificate
451
- fields = object.keys.reject{ |k| k.eql?('certificate')}
452
- return Main.result_single_object(object, fields: fields)
466
+ object = aoc_api.read(resource_instance_path, query_read_delete)
467
+ return Main.result_single_object(object, fields: Formatter.all_but('certificate'))
453
468
  when :modify
454
469
  changes = options.get_next_argument('properties', validation: Hash)
455
470
  return do_bulk_operation(command: command, values: res_id) do |one_id|
@@ -468,7 +483,7 @@ module Aspera
468
483
  aoc_api.update(resource_instance_path, {jwt_grant_enabled: true, public_key: the_public_key})
469
484
  return Main.result_success
470
485
  when :do
471
- command_repo = options.get_next_command(NODE4_EXT_COMMANDS)
486
+ command_repo = options.get_next_command(FILES_COMMANDS)
472
487
  return execute_nodegen4_command(command_repo, res_id, scope: Api::Node::Scope::ADMIN)
473
488
  when :bearer_token
474
489
  node_api = aoc_api.node_api_from(
@@ -493,7 +508,7 @@ module Aspera
493
508
  when :list
494
509
  return Main.result_object_list(shared_folders, fields: %w[id node_name node_id file_id file.path tags.aspera.files.workspace.share_as])
495
510
  when :member
496
- shared_folder_id = instance_identifier
511
+ shared_folder_id = options.instance_identifier
497
512
  shared_folder = shared_folders.find{ |i| i['id'].eql?(shared_folder_id)}
498
513
  Aspera.assert(shared_folder)
499
514
  command_shared_member = options.get_next_command(%i[list])
@@ -524,11 +539,75 @@ module Aspera
524
539
  return Main.result_object_list(result, fields: %w[access_type access_id access_level last_updated_at member.name member.email member.system_group_type member.system_group])
525
540
  end
526
541
  end
542
+ when :preferences, :notifications
543
+ user_preferences_res = "#{resource_instance_path}/#{command.eql?(:preferences) ? 'user_interaction_preferences' : 'notification_preferences'}"
544
+ case options.get_next_command(%i[show modify])
545
+ when :show
546
+ return Main.result_single_object(aoc_api.read(user_preferences_res))
547
+ when :modify
548
+ aoc_api.update(user_preferences_res, options.get_next_argument('properties', validation: Hash))
549
+ return Main.result_status('modified')
550
+ end
527
551
  else Aspera.error_unexpected_value(command)
528
552
  end
529
553
  end
530
554
 
531
- ADMIN_ACTIONS = %i[ats bearer_token resource usage_reports analytics subscription auth_providers].concat(ADMIN_OBJECTS).freeze
555
+ def execute_application_action
556
+ apps_info = aoc_api.read('admin/apps')
557
+ all_app_types = apps_info.map{ |i| i['app_type'].to_sym}
558
+ command_apps = options.get_next_command(%i[types settings instance membership])
559
+ case command_apps
560
+ when :types
561
+ return Main.result_object_list(apps_info)
562
+ when :settings
563
+ app_type = options.get_next_command(all_app_types)
564
+ cmd_path = "/apps/#{app_type}/settings"
565
+ command_app_settings = options.get_next_command(Operations::SINGLETON)
566
+ case command_app_settings
567
+ when :show
568
+ return Main.result_single_object(aoc_api.read(cmd_path))
569
+ when :modify
570
+ aoc_api.update(cmd_path, options.get_next_argument('properties', validation: Hash))
571
+ return Main.result_status('modified')
572
+ end
573
+ when :instance
574
+ list_default_query = {workspace_id: aoc_api.workspace_info[:id]}
575
+ list_default_fields = %w[id app_type available workspace_id]
576
+ command_app_instances = options.get_next_command(%i[list] + Operations::SINGLETON)
577
+ resource_path = 'admin/apps_new'
578
+ if Operations::SINGLETON.include?(command_app_instances)
579
+ app_type = options.get_next_command(all_app_types)
580
+ resource_path = "#{resource_path}/#{app_type}/#{options.instance_identifier(description: "#{app_type} identifier")}"
581
+ end
582
+ case command_app_instances
583
+ when :list
584
+ return result_list(resource_path, fields: list_default_fields, default_query: list_default_query)
585
+ when :show
586
+ return Main.result_single_object(aoc_api.read(resource_path, query_read_delete))
587
+ when :modify
588
+ aoc_api.update(resource_path, options.get_next_argument('properties', validation: Hash))
589
+ return Main.result_status('modified')
590
+ end
591
+ when :membership
592
+ resource_path = 'apps/app_memberships'
593
+ command_app_member = options.get_next_command(%i[create list show delete])
594
+ resource_path = "#{resource_path}/#{options.instance_identifier(description: 'membership id')}" unless Operations::GLOBAL.include?(command_app_member)
595
+ case command_app_member
596
+ when :list
597
+ return result_list(resource_path)
598
+ when :delete
599
+ aoc_api.delete("#{resource_path}}")
600
+ return Main.result_status('deleted')
601
+ when :show
602
+ return Main.result_single_object(aoc_api.read(resource_path, query_read_delete))
603
+ when :create
604
+ aoc_api.update(resource_path, options.get_next_argument('membership properties', validation: Hash))
605
+ return Main.result_status('modified')
606
+ end
607
+ end
608
+ end
609
+
610
+ ADMIN_ACTIONS = %i[bearer_token application ats usage_reports analytics subscription auth_providers].concat(ADMIN_OBJECTS).freeze
532
611
 
533
612
  def execute_admin_action
534
613
  # change scope to admin
@@ -537,11 +616,10 @@ module Aspera
537
616
  case command_admin
538
617
  when :bearer_token
539
618
  return Main.result_text(aoc_api.oauth.authorization)
540
- when :resource
541
- Log.log.warn('resource command is deprecated (4.18), directly use the specific command instead')
542
- return execute_resource_action(options.get_next_argument('resource', accept_list: ADMIN_OBJECTS))
543
619
  when *ADMIN_OBJECTS
544
620
  return execute_resource_action(command_admin)
621
+ when :application
622
+ return execute_application_action
545
623
  when :auth_providers
546
624
  command_auth_prov = options.get_next_command(%i[list update])
547
625
  case command_auth_prov
@@ -699,7 +777,7 @@ module Aspera
699
777
  id: IdGenerator.from_list(
700
778
  'aoc_ana_date',
701
779
  options.get_option(:url, mandatory: true),
702
- aoc_api.workspace[:name],
780
+ aoc_api.workspace_info[:name],
703
781
  event_resource_type.to_s,
704
782
  event_resource_id
705
783
  )
@@ -721,7 +799,7 @@ module Aspera
721
799
  when :files
722
800
  event_type = command_analytics.to_s
723
801
  event_resource_type = options.get_next_argument('resource', accept_list: %i[organizations users nodes])
724
- event_resource_id = instance_identifier(description: "#{event_resource_type} identifier")
802
+ event_resource_id = options.instance_identifier(description: "#{event_resource_type} identifier")
725
803
  event_resource_id =
726
804
  case event_resource_type
727
805
  when :organizations then aoc_api.current_user_info['organization_id']
@@ -729,7 +807,7 @@ module Aspera
729
807
  when :nodes then aoc_api.current_user_info['read_only_home_node_id']
730
808
  else Aspera.error_unreachable_line
731
809
  end if event_resource_id.empty?
732
- event_uuid = instance_identifier(description: 'event uuid')
810
+ event_uuid = options.instance_identifier(description: 'event uuid')
733
811
  filter = query_read_delete(default: {})
734
812
  filter['limit'] ||= 100
735
813
  events = analytics_api.read("#{event_resource_type}/#{event_resource_id}/transfers/#{event_uuid}/#{event_type}", filter)[event_type]
@@ -818,7 +896,7 @@ module Aspera
818
896
  short_list = aoc_api.read_with_paging('short_links', list_params.merge(query_read_delete(default: {})).compact)
819
897
  case command
820
898
  when :delete
821
- one_id = instance_identifier(description: 'short link id')
899
+ one_id = options.instance_identifier(description: 'short link id')
822
900
  if link_type.eql?(:public)
823
901
  found = short_list[:items].find{ |item| item['id'].eql?(one_id)}
824
902
  raise BadIdentifier.new('Short link', one_id) if found.nil?
@@ -832,12 +910,12 @@ module Aspera
832
910
  when :list
833
911
  return Main.result_object_list(short_list[:items], fields: Formatter.all_but('data'), total: short_list[:total])
834
912
  when :show
835
- one_id = instance_identifier(description: 'short link id')
913
+ one_id = options.instance_identifier(description: 'short link id')
836
914
  found = short_list[:items].find{ |item| item['id'].eql?(one_id)}
837
915
  raise BadIdentifier.new('Short link', one_id) if found.nil?
838
916
  return Main.result_single_object(found, fields: Formatter.all_but('data'))
839
917
  when :modify
840
- one_id = instance_identifier(description: 'short link id')
918
+ one_id = options.instance_identifier(description: 'short link id')
841
919
  node_file = shared_data.slice(:node_id, :file_id)
842
920
  modify_payload = {
843
921
  edit_access: true,
@@ -879,7 +957,7 @@ module Aspera
879
957
  id: IdGenerator.from_list(
880
958
  'aoc_recv',
881
959
  options.get_option(:url, mandatory: true),
882
- aoc_api.workspace[:id],
960
+ aoc_api.workspace_info[:id],
883
961
  aoc_api.additional_persistence_ids
884
962
  )
885
963
  )
@@ -897,8 +975,7 @@ module Aspera
897
975
  def execute_action
898
976
  command = options.get_next_command(ACTIONS)
899
977
  if %i[files packages].include?(command)
900
- default_flag = ' (default)' if options.get_option(:workspace).eql?(:default)
901
- formatter.display_status("Workspace: #{aoc_api.workspace[:name].to_s.red}#{default_flag}")
978
+ formatter.display_status("Workspace: #{aoc_api.workspace_info[:name].to_s.red}#{' (default)' if aoc_api.default_workspace?}")
902
979
  if !aoc_api.private_link.nil?
903
980
  folder_name = aoc_api.node_api_from(node_id: aoc_api.home[:node_id]).read("files/#{aoc_api.home[:file_id]}")['name']
904
981
  formatter.display_status("Private Folder: #{folder_name}")
@@ -919,7 +996,8 @@ module Aspera
919
996
  when :tier_restrictions
920
997
  return Main.result_single_object(aoc_api.read('tier_restrictions'))
921
998
  when :user
922
- case options.get_next_command(%i[workspaces profile preferences contacts])
999
+ user_cmd = options.get_next_command(%i[workspaces profile preferences notifications contacts])
1000
+ case user_cmd
923
1001
  when :contacts
924
1002
  return execute_resource_action(:contact)
925
1003
  # when :settings
@@ -929,7 +1007,7 @@ module Aspera
929
1007
  when :list
930
1008
  return result_list('workspaces', fields: %w[id name])
931
1009
  when :current
932
- return Main.result_single_object(aoc_api.workspace)
1010
+ return Main.result_single_object(aoc_api.workspace_info)
933
1011
  end
934
1012
  when :profile
935
1013
  case options.get_next_command(%i[show modify])
@@ -939,8 +1017,8 @@ module Aspera
939
1017
  aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}", options.get_next_argument('properties', validation: Hash))
940
1018
  return Main.result_status('modified')
941
1019
  end
942
- when :preferences
943
- user_preferences_res = "users/#{aoc_api.current_user_info(exception: true)['id']}/user_interaction_preferences"
1020
+ when :preferences, :notifications
1021
+ user_preferences_res = "users/#{aoc_api.current_user_info(exception: true)['id']}/#{user_cmd.eql?(:preferences) ? 'user_interaction_preferences' : 'notification_preferences'}"
944
1022
  case options.get_next_command(%i[show modify])
945
1023
  when :show
946
1024
  return Main.result_single_object(aoc_api.read(user_preferences_res))
@@ -991,7 +1069,7 @@ module Aspera
991
1069
  ids_to_download = aoc_api.public_link['data']['package_id']
992
1070
  end
993
1071
  # Get from command line unless it was a public link
994
- ids_to_download ||= instance_identifier
1072
+ ids_to_download ||= options.instance_identifier
995
1073
  skip_ids_persistency = package_persistency
996
1074
  case ids_to_download
997
1075
  when SpecialValues::INIT
@@ -1046,7 +1124,7 @@ module Aspera
1046
1124
  end
1047
1125
  return Main.result_transfer_multiple(result_transfer)
1048
1126
  when :show
1049
- package_id = instance_identifier
1127
+ package_id = options.instance_identifier
1050
1128
  package_info = aoc_api.read("packages/#{package_id}")
1051
1129
  return Main.result_single_object(package_info)
1052
1130
  when :list
@@ -1054,27 +1132,27 @@ module Aspera
1054
1132
  skip_ids_persistency = package_persistency
1055
1133
  reject_packages_from_persistency(result[:items], skip_ids_persistency)
1056
1134
  display_fields = PACKAGE_LIST_DEFAULT_FIELDS
1057
- display_fields += ['workspace_id'] if aoc_api.workspace[:id].nil?
1135
+ display_fields += ['workspace_id'] if aoc_api.workspace_info[:id].nil?
1058
1136
  return Main.result_object_list(result[:items], fields: display_fields, total: result[:total])
1059
1137
  when :delete
1060
- return do_bulk_operation(command: package_command, values: instance_identifier) do |id|
1061
- Aspera.assert_type(id, String, Integer){'identifier'}
1062
- aoc_api.delete("packages/#{id}")
1138
+ return do_bulk_operation(command: package_command, values: options.instance_identifier) do |package_id|
1139
+ Aspera.assert_type(package_id, String, Integer){'identifier'}
1140
+ aoc_api.delete("packages/#{package_id}")
1063
1141
  end
1064
1142
  when :modify
1065
- id = instance_identifier
1143
+ package_id = options.instance_identifier
1066
1144
  package_data = value_create_modify(command: package_command)
1067
- aoc_api.update("packages/#{id}", package_data)
1145
+ aoc_api.update("packages/#{package_id}", package_data)
1068
1146
  return Main.result_status('modified')
1069
1147
  when *Node::NODE4_READ_ACTIONS
1070
- package_id = instance_identifier
1148
+ package_id = options.instance_identifier
1071
1149
  package_info = aoc_api.read("packages/#{package_id}")
1072
1150
  return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['contents_file_id'], scope: Api::Node::Scope::USER)
1073
1151
  end
1074
1152
  when :files
1075
- command_repo = options.get_next_command([:short_link].concat(NODE4_EXT_COMMANDS))
1153
+ command_repo = options.get_next_command([:short_link].concat(FILES_COMMANDS))
1076
1154
  case command_repo
1077
- when *NODE4_EXT_COMMANDS
1155
+ when *FILES_COMMANDS
1078
1156
  return execute_nodegen4_command(command_repo, aoc_api.home[:node_id], file_id: aoc_api.home[:file_id], scope: Api::Node::Scope::USER)
1079
1157
  when :short_link
1080
1158
  folder_dest = options.get_next_argument('path', validation: String)
@@ -1082,16 +1160,16 @@ module Aspera
1082
1160
  node_id: aoc_api.home[:node_id],
1083
1161
  **workspace_id_hash(name: true)
1084
1162
  )
1085
- shared_apfid = home_node_api.resolve_api_fid(aoc_api.home[:file_id], folder_dest)
1163
+ shared_apifid = home_node_api.resolve_api_fid(aoc_api.home[:file_id], folder_dest)
1086
1164
  return short_link_command(
1087
- node_id: shared_apfid[:api].app_info[:node_info]['id'],
1088
- file_id: shared_apfid[:file_id]
1165
+ node_id: shared_apifid.node_api.app_info.node_info['id'],
1166
+ file_id: shared_apifid.file_id
1089
1167
  ) do |op, id, access_levels|
1090
1168
  case op
1091
1169
  when :create
1092
1170
  # `id` is the resource id
1093
1171
  perm_data = {
1094
- 'file_id' => shared_apfid[:file_id],
1172
+ 'file_id' => shared_apifid.file_id,
1095
1173
  'access_id' => id,
1096
1174
  'access_type' => 'user',
1097
1175
  'access_levels' => Api::AoC.expand_access_levels(access_levels),
@@ -1100,23 +1178,23 @@ module Aspera
1100
1178
  'folder_name' => File.basename(folder_dest),
1101
1179
  'created_by_name' => aoc_api.current_user_info['name'],
1102
1180
  'created_by_email' => aoc_api.current_user_info['email'],
1103
- 'access_key' => shared_apfid[:api].app_info[:node_info]['access_key'],
1104
- 'node' => shared_apfid[:api].app_info[:node_info]['name'],
1181
+ 'access_key' => shared_apifid.node_api.app_info.node_info['access_key'],
1182
+ 'node' => shared_apifid.node_api.app_info.node_info['name'],
1105
1183
  **workspace_id_hash(string: true, name: true)
1106
1184
  }
1107
1185
  }
1108
- created_data = shared_apfid[:api].create('permissions', perm_data)
1109
- aoc_api.permissions_send_event(event_data: created_data, app_info: shared_apfid[:api].app_info)
1186
+ created_data = shared_apifid.node_api.create('permissions', perm_data)
1187
+ aoc_api.permissions_send_event(event_data: created_data, app_info: shared_apifid.node_api.app_info)
1110
1188
  when :update
1111
1189
  # `id` is the permission_id
1112
- found = shared_apfid[:api].read('permissions', {file_id: shared_apfid[:file_id], inherited: false, access_type: 'user', access_id: id}).find{ |i| i['access_id'].eql?(id)}
1113
- raise Error, 'Short link not found: #{id}' if found.nil?
1114
- shared_apfid[:api].update("permissions/#{found['id']}", {access_levels: Api::AoC.expand_access_levels(access_levels)})
1190
+ found = shared_apifid.node_api.read('permissions', {file_id: shared_apifid.file_id, inherited: false, access_type: 'user', access_id: id}).find{ |i| i['access_id'].eql?(id)}
1191
+ raise Error, "Short link not found: #{id}" if found.nil?
1192
+ shared_apifid.node_api.update("permissions/#{found['id']}", {access_levels: Api::AoC.expand_access_levels(access_levels)})
1115
1193
  when :delete
1116
1194
  # `id` is the resource id, i.e. `access_id`
1117
- found = shared_apfid[:api].read('permissions', {file_id: shared_apfid[:file_id], inherited: false, access_type: 'user', access_id: id}).first
1118
- raise Error, 'Short link not found: #{id}' if found.nil?
1119
- shared_apfid[:api].delete("permissions/#{found['id']}")
1195
+ found = shared_apifid.node_api.read('permissions', {file_id: shared_apifid.file_id, inherited: false, access_type: 'user', access_id: id}).first
1196
+ raise Error, "Short link not found: #{id}" if found.nil?
1197
+ shared_apifid.node_api.delete("permissions/#{found['id']}")
1120
1198
  else Aspera.error_unexpected_value(op)
1121
1199
  end
1122
1200
  end
@@ -1131,21 +1209,21 @@ module Aspera
1131
1209
  when :instances
1132
1210
  return entity_execute(api: aoc_api, entity: 'workflow_instances')
1133
1211
  when :workflows
1134
- wf_command = options.get_next_command(%i[action launch].concat(ALL_OPS))
1212
+ wf_command = options.get_next_command(%i[action launch].concat(Operations::ALL))
1135
1213
  case wf_command
1136
- when *ALL_OPS
1214
+ when *Operations::ALL
1137
1215
  return entity_execute(
1138
1216
  api: automation_api,
1139
1217
  entity: 'workflows',
1140
1218
  command: wf_command
1141
1219
  )
1142
1220
  when :launch
1143
- wf_id = instance_identifier
1221
+ wf_id = options.instance_identifier
1144
1222
  data = automation_api.create("workflows/#{wf_id}/launch", {})
1145
1223
  return Main.result_single_object(data)
1146
1224
  when :action
1147
1225
  # TODO: not complete
1148
- wf_id = instance_identifier
1226
+ wf_id = options.instance_identifier
1149
1227
  wf_action_cmd = options.get_next_command(%i[list create show])
1150
1228
  Log.log.warn{"Not implemented: #{wf_action_cmd}"}
1151
1229
  step = automation_api.create('steps', {'workflow_id' => wf_id})
@@ -1164,7 +1242,7 @@ module Aspera
1164
1242
  uri = URI.parse(parameters.delete(:url){WebServerSimple::DEFAULT_URL})
1165
1243
  server = WebServerSimple.new(uri, **parameters.slice(*WebServerSimple::PARAMS))
1166
1244
  Aspera.assert(parameters.except(*WebServerSimple::PARAMS).empty?)
1167
- server.mount(uri.path, Faspex4GWServlet, aoc_api, aoc_api.workspace[:id])
1245
+ server.mount(uri.path, Faspex4GWServlet, aoc_api, aoc_api.workspace_info[:id])
1168
1246
  server.start
1169
1247
  return Main.result_status('Gateway terminated')
1170
1248
  else Aspera.error_unreachable_line