aspera-cli 4.26.0 → 4.26.2

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 (99) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +36 -4
  4. data/CONTRIBUTING.md +2 -5
  5. data/bin/ascli +2 -2
  6. data/lib/aspera/agent/direct.rb +1 -1
  7. data/lib/aspera/agent/factory.rb +4 -0
  8. data/lib/aspera/agent/httpgw.rb +1 -1
  9. data/lib/aspera/agent/node.rb +2 -2
  10. data/lib/aspera/api/aoc.rb +45 -37
  11. data/lib/aspera/api/cos_node.rb +1 -1
  12. data/lib/aspera/api/faspex.rb +7 -6
  13. data/lib/aspera/api/node.rb +9 -9
  14. data/lib/aspera/ascmd.rb +4 -4
  15. data/lib/aspera/ascp/installation.rb +13 -6
  16. data/lib/aspera/assert.rb +17 -13
  17. data/lib/aspera/cli/context.rb +58 -0
  18. data/lib/aspera/cli/extended_value.rb +9 -4
  19. data/lib/aspera/cli/formatter.rb +91 -187
  20. data/lib/aspera/cli/http.rb +167 -0
  21. data/lib/aspera/cli/manager.rb +132 -77
  22. data/lib/aspera/cli/options.schema.yaml +82 -0
  23. data/lib/aspera/cli/plugins/alee.rb +2 -2
  24. data/lib/aspera/cli/plugins/aoc.rb +113 -77
  25. data/lib/aspera/cli/plugins/ats.rb +16 -16
  26. data/lib/aspera/cli/plugins/base.rb +64 -49
  27. data/lib/aspera/cli/plugins/config.rb +172 -444
  28. data/lib/aspera/cli/plugins/console.rb +7 -7
  29. data/lib/aspera/cli/plugins/cos.rb +2 -2
  30. data/lib/aspera/cli/plugins/factory.rb +3 -0
  31. data/lib/aspera/cli/plugins/faspex.rb +22 -22
  32. data/lib/aspera/cli/plugins/faspex5.rb +68 -49
  33. data/lib/aspera/cli/plugins/faspio.rb +1 -1
  34. data/lib/aspera/cli/plugins/httpgw.rb +2 -2
  35. data/lib/aspera/cli/plugins/node.rb +80 -80
  36. data/lib/aspera/cli/plugins/orchestrator.rb +21 -26
  37. data/lib/aspera/cli/plugins/preview.rb +9 -9
  38. data/lib/aspera/cli/plugins/server.rb +7 -7
  39. data/lib/aspera/cli/plugins/shares.rb +2 -2
  40. data/lib/aspera/cli/preset_manager.rb +235 -0
  41. data/lib/aspera/cli/result.rb +310 -0
  42. data/lib/aspera/cli/{main.rb → runner.rb} +48 -130
  43. data/lib/aspera/cli/sync_actions.rb +15 -11
  44. data/lib/aspera/cli/terminal_formatter.rb +65 -0
  45. data/lib/aspera/cli/transfer_agent.rb +17 -15
  46. data/lib/aspera/cli/transfer_progress.rb +6 -6
  47. data/lib/aspera/cli/version.rb +1 -1
  48. data/lib/aspera/cli/wizard.rb +5 -6
  49. data/lib/aspera/command_line_builder.rb +22 -18
  50. data/lib/aspera/data_repository.rb +4 -0
  51. data/lib/aspera/dot_container.rb +1 -1
  52. data/lib/aspera/environment.rb +25 -6
  53. data/lib/aspera/faspex_gw.rb +1 -1
  54. data/lib/aspera/formatter_interface.rb +14 -0
  55. data/lib/aspera/hash_ext.rb +6 -0
  56. data/lib/aspera/json_rpc.rb +6 -5
  57. data/lib/aspera/keychain/base.rb +1 -1
  58. data/lib/aspera/keychain/encrypted_hash.rb +1 -1
  59. data/lib/aspera/keychain/factory.rb +1 -1
  60. data/lib/aspera/keychain/macos_security.rb +1 -1
  61. data/lib/aspera/log.rb +10 -5
  62. data/lib/aspera/markdown.rb +4 -1
  63. data/lib/aspera/nagios.rb +2 -2
  64. data/lib/aspera/oauth/base.rb +5 -5
  65. data/lib/aspera/oauth/boot.rb +43 -0
  66. data/lib/aspera/oauth/factory.rb +38 -14
  67. data/lib/aspera/oauth/web.rb +2 -2
  68. data/lib/aspera/oauth.rb +1 -0
  69. data/lib/aspera/persistency_action_once.rb +2 -2
  70. data/lib/aspera/preview/file_types.rb +4 -0
  71. data/lib/aspera/products/connect.rb +3 -0
  72. data/lib/aspera/products/transferd.rb +2 -2
  73. data/lib/aspera/proxy_auto_config.rb +6 -3
  74. data/lib/aspera/rest.rb +9 -5
  75. data/lib/aspera/rest_error_analyzer.rb +4 -0
  76. data/lib/aspera/rest_list.rb +10 -3
  77. data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +62811 -0
  78. data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +9637 -0
  79. data/lib/aspera/schema/async_tables.yaml +361 -0
  80. data/lib/aspera/schema/documentation.rb +107 -0
  81. data/lib/aspera/schema/reader.rb +75 -0
  82. data/lib/aspera/schema/registry.rb +70 -0
  83. data/lib/aspera/secret_hider.rb +4 -0
  84. data/lib/aspera/sync/conf.schema.yaml +0 -26
  85. data/lib/aspera/sync/database.rb +14 -10
  86. data/lib/aspera/sync/operations.rb +14 -10
  87. data/lib/aspera/temp_file_manager.rb +4 -0
  88. data/lib/aspera/transfer/faux_file.rb +1 -1
  89. data/lib/aspera/transfer/parameters.rb +4 -4
  90. data/lib/aspera/transfer/resumer.rb +2 -2
  91. data/lib/aspera/transfer/spec.rb +3 -3
  92. data/lib/aspera/transfer/spec.schema.yaml +18 -9
  93. data/lib/aspera/transfer/uri.rb +1 -1
  94. data/lib/aspera/uri_reader.rb +1 -1
  95. data/lib/aspera/yaml.rb +4 -2
  96. data.tar.gz.sig +0 -0
  97. metadata +28 -15
  98. metadata.gz.sig +1 -1
  99. data/lib/aspera/transfer/spec_doc.rb +0 -76
@@ -27,12 +27,14 @@ module Aspera
27
27
  client
28
28
  client_access_key
29
29
  client_registration_token
30
+ configuration_policy
30
31
  contact
31
32
  dropbox
32
33
  dropbox_membership
33
34
  group
34
35
  group_membership
35
36
  kms_profile
37
+ network_policy
36
38
  node
37
39
  operation
38
40
  organization
@@ -100,7 +102,7 @@ module Aspera
100
102
  # @param fld. [Array] List of fields of package
101
103
  def unique_folder(package_info, destination_folder, fld: nil, seq: false, opt: false)
102
104
  Aspera.assert_array_all(fld, String, type: BadArgument){'fld'}
103
- Aspera.assert([1, 2].include?(fld.length)){'fld must have 1 or 2 elements'}
105
+ Aspera.assert_values(fld.length, [1, 2]){'fld length'}
104
106
  folder = Environment.instance.sanitized_filename(package_info[fld[0]])
105
107
  if seq
106
108
  folder = next_available_folder(folder, always: !opt)
@@ -178,7 +180,7 @@ module Aspera
178
180
  end
179
181
  myself = aoc_api.read('self')
180
182
  if auto_set_pub_key
181
- Aspera.assert(myself['public_key'].empty?, type: Error){'Public key is already set in profile (use --override=yes)'} unless option_override
183
+ Aspera.assert(myself['public_key'].empty?, 'Public key is already set in profile (use --override=yes)', type: Error) unless option_override
182
184
  formatter.display_status('Updating profile with the public key.')
183
185
  aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
184
186
  end
@@ -289,7 +291,7 @@ module Aspera
289
291
  # @return identifier
290
292
  def get_resource_id_from_args(resource_class_path)
291
293
  return options.instance_identifier do |field, value|
292
- Aspera.assert(field.eql?('name'), type: BadArgument){'only selection by name is supported'}
294
+ Aspera.assert_values(field, ['name'], type: BadArgument){'selector field'}
293
295
  aoc_api.lookup_with_q(resource_class_path, value: value)['id']
294
296
  end
295
297
  end
@@ -304,7 +306,7 @@ module Aspera
304
306
  # @param fields fields to display
305
307
  # @param base_query a query applied always
306
308
  # @param default_query default query unless overridden by user
307
- # @param &block (Optional) calls block with user's or default query
309
+ # @yieldparam query [Hash] The user's or default query for modification
308
310
  def result_list(resource_class_path, fields: nil, base_query: {}, default_query: {})
309
311
  Aspera.assert_type(base_query, Hash)
310
312
  Aspera.assert_type(default_query, Hash)
@@ -312,7 +314,7 @@ module Aspera
312
314
  # caller may add specific modifications or checks to query
313
315
  yield(query) if block_given?
314
316
  result = aoc_api.read_with_paging(resource_class_path, base_query.merge(query).compact)
315
- return Main.result_object_list(result[:items], fields: fields, total: result[:total])
317
+ return Result::ObjectList.new(result[:items], fields: fields, total: result[:total])
316
318
  end
317
319
 
318
320
  # Translates `dropbox_name` to `dropbox_id` and fills current workspace_id
@@ -389,7 +391,7 @@ module Aspera
389
391
  'destination_root_id' => server_apifid.file_id,
390
392
  'source_root_id' => client_apifid.file_id
391
393
  }
392
- return Main.result_transfer(transfer.start(server_apifid.node_api.transfer_spec_gen4(
394
+ return Runner.result_transfer(transfer.start(server_apifid.node_api.transfer_spec_gen4(
393
395
  server_apifid.file_id,
394
396
  client_direction,
395
397
  add_ts
@@ -402,34 +404,53 @@ module Aspera
402
404
  # Execute an action on admin resources
403
405
  # @param resource_type [Symbol] One of ADMIN_OBJECTS
404
406
  def execute_resource_action(resource_type)
407
+ # Set to `true` is resource creation requires a workspace id
405
408
  require_workspace_id = false
409
+ # Default fields to display
406
410
  list_default_fields = %w[id name]
411
+ # Default query for `list` action
407
412
  list_default_query = {}
413
+ # In result of create, what is the field that contains the id of the created resource
414
+ id_result = 'id'
408
415
  supported_operations = Operations::ALL
416
+ # API path
409
417
  resource_class_path = "#{resource_type}s"
418
+ resource_class_path = resource_class_path.gsub(/ys$/, 'ies')
419
+ # path in openapi where post is located to get creation schema
420
+ create_schema_path = resource_class_path
410
421
  case resource_type
411
422
  when :client
412
423
  supported_operations += %i[set_pub_key]
424
+ # schema_create_modify = Schema::Registry.req_body(Schema::Registry::AOC, "#{resource_class_path}.post")
413
425
  when :client_access_key
414
426
  resource_class_path = "admin/#{resource_type}s"
415
427
  when :client_registration_token
416
428
  resource_class_path = "admin/#{resource_type}s"
417
- list_default_fields = %w[id value data.client_subject_scopes created_at]
429
+ list_default_fields = %w[id value data.client_subject_scopes data.name created_at]
430
+ id_result = 'token'
418
431
  when :contact
419
432
  list_default_fields = %w[source_type source_id name email]
420
433
  # list_default_query = {'include_only_user_personal_contacts' => true} if @scope == Api::AoC::Scope::USER
434
+ when :configuration_policy, :network_policy
435
+ list_default_fields = nil
421
436
  when :dropbox
422
437
  require_workspace_id = true
423
438
  resource_class_path = "#{resource_type}es"
439
+ create_schema_path = resource_class_path
440
+ when :group, :saml_configuration
441
+ create_schema_path = nil
424
442
  when :group_membership
425
443
  list_default_fields = %w[id group_id member_type member_id]
444
+ create_schema_path = nil
426
445
  when :kms_profile
427
446
  resource_class_path = "integrations/#{resource_type}s"
447
+ create_schema_path = nil
428
448
  when :node
429
449
  list_default_fields = %w[id name host access_key]
430
450
  supported_operations += %i[do bearer_token]
431
451
  when :operation
432
- list_default_fields = nil
452
+ list_default_fields = %w[id type status created_at updated_at workspace_id user_id workspace_membership_id group_membership_id]
453
+ supported_operations = %i[list show modify]
433
454
  when :organization, :self
434
455
  supported_operations = Operations::SINGLETON
435
456
  resource_instance_path = resource_class_path = resource_type
@@ -443,6 +464,8 @@ module Aspera
443
464
  when :workspace_membership
444
465
  list_default_fields = %w[id workspace_id member_type member_id]
445
466
  end
467
+ # Default location of creation payload in schema
468
+ schema_create_modify = Schema::Registry.req_body(Schema::Registry::AOC, "#{create_schema_path}.post") if create_schema_path && supported_operations.include?(:create)
446
469
  command = options.get_next_command(supported_operations)
447
470
  # Require identifier for non global commands
448
471
  if (supported_operations != Operations::SINGLETON) && !Operations::GLOBAL.include?(command)
@@ -451,12 +474,10 @@ module Aspera
451
474
  end
452
475
  case command
453
476
  when :create
454
- id_result = 'id'
455
- id_result = 'token' if resource_class_path.eql?('admin/client_registration_tokens')
456
477
  # TODO: report inconsistency: creation url is !=, and does not return id.
457
478
  resource_class_path = 'admin/client_registration/token' if resource_class_path.eql?('admin/client_registration_tokens')
458
479
  workspace_id = aoc_api.workspace_info[:id] if require_workspace_id
459
- return do_bulk_operation(command: command, descr: 'creation data', id_result: id_result) do |params|
480
+ return do_bulk_operation(command: command, descr: 'creation data', id_result: id_result, schema: schema_create_modify) do |params|
460
481
  params['workspace_id'] = workspace_id if require_workspace_id && workspace_id && !params.key?('workspace_id')
461
482
  aoc_api.create(resource_class_path, params)
462
483
  end
@@ -464,9 +485,9 @@ module Aspera
464
485
  return result_list(resource_class_path, fields: list_default_fields, default_query: list_default_query)
465
486
  when :show
466
487
  object = aoc_api.read(resource_instance_path, query_read_delete)
467
- return Main.result_single_object(object, fields: Formatter.all_but('certificate'))
488
+ return Result::SingleObject.new(object, fields: Formatter.all_but('certificate'))
468
489
  when :modify
469
- changes = options.get_next_argument('properties', validation: Hash)
490
+ changes = options.get_next_argument('properties', validation: Hash, schema: schema_create_modify)
470
491
  return do_bulk_operation(command: command, values: res_id) do |one_id|
471
492
  aoc_api.update("#{resource_class_path}/#{one_id}", changes)
472
493
  {'id' => one_id}
@@ -481,7 +502,7 @@ module Aspera
481
502
  the_private_key = options.get_next_argument('private_key PEM value', validation: String)
482
503
  the_public_key = OpenSSL::PKey::RSA.new(the_private_key).public_key.to_s
483
504
  aoc_api.update(resource_instance_path, {jwt_grant_enabled: true, public_key: the_public_key})
484
- return Main.result_success
505
+ return Result::Success.new
485
506
  when :do
486
507
  command_repo = options.get_next_command(FILES_COMMANDS)
487
508
  return execute_nodegen4_command(command_repo, res_id, scope: Api::Node::Scope::ADMIN)
@@ -490,27 +511,33 @@ module Aspera
490
511
  node_id: res_id,
491
512
  scope: options.get_next_argument('scope', default: Api::Node::Scope::ADMIN)
492
513
  )
493
- return Main.result_text(node_api.oauth.authorization)
514
+ return Result::Text.new(node_api.oauth.authorization)
494
515
  when :dropbox
495
516
  command_shared = options.get_next_command(%i[list])
496
517
  case command_shared
497
518
  when :list
498
519
  query = options.get_option(:query) || {}
499
520
  res_data = aoc_api.read('dropboxes', query.merge({'workspace_id'=>res_id}))
500
- return Main.result_object_list(res_data, fields: %w[id name description])
521
+ return Result::ObjectList.new(res_data, fields: %w[id name description])
501
522
  end
502
523
  when :shared_folder
503
524
  query = options.get_option(:query) || Api::AoC.workspace_access(res_id).merge({'admin' => true})
504
525
  shared_folders = aoc_api.read_with_paging("#{resource_instance_path}/permissions", query)[:items]
505
526
  # inside a workspace
506
- command_shared = options.get_next_command(%i[list member])
527
+ command_shared = options.get_next_command(%i[list node member])
507
528
  case command_shared
508
529
  when :list
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])
530
+ return Result::ObjectList.new(shared_folders, fields: %w[id node_name node_id file_id file.path tags.aspera.files.workspace.share_as])
531
+ when :node
532
+ shared_folder_id = options.instance_identifier(description: 'Shared folder ID')
533
+ shared_folder = shared_folders.find{ |i| i['id'].eql?(shared_folder_id)}
534
+ Aspera.assert(shared_folder, 'shared folder not found')
535
+ command_repo = options.get_next_command(FILES_COMMANDS)
536
+ return execute_nodegen4_command(command_repo, shared_folder['node_id'], file_id: shared_folder['file_id'], scope: Api::Node::Scope::ADMIN)
510
537
  when :member
511
- shared_folder_id = options.instance_identifier
538
+ shared_folder_id = options.instance_identifier(description: 'Shared folder ID')
512
539
  shared_folder = shared_folders.find{ |i| i['id'].eql?(shared_folder_id)}
513
- Aspera.assert(shared_folder)
540
+ Aspera.assert(shared_folder, 'shared folder not found')
514
541
  command_shared_member = options.get_next_command(%i[list])
515
542
  case command_shared_member
516
543
  when :list
@@ -536,17 +563,17 @@ module Aspera
536
563
  end
537
564
  end
538
565
  # TODO : read users and group name and add, if query "include_members"
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])
566
+ return Result::ObjectList.new(result, fields: %w[access_type access_id access_level last_updated_at member.name member.email member.system_group_type member.system_group])
540
567
  end
541
568
  end
542
569
  when :preferences, :notifications
543
570
  user_preferences_res = "#{resource_instance_path}/#{command.eql?(:preferences) ? 'user_interaction_preferences' : 'notification_preferences'}"
544
571
  case options.get_next_command(%i[show modify])
545
572
  when :show
546
- return Main.result_single_object(aoc_api.read(user_preferences_res))
573
+ return Result::SingleObject.new(aoc_api.read(user_preferences_res))
547
574
  when :modify
548
575
  aoc_api.update(user_preferences_res, options.get_next_argument('properties', validation: Hash))
549
- return Main.result_status('modified')
576
+ return Result::Status.new('modified')
550
577
  end
551
578
  else Aspera.error_unexpected_value(command)
552
579
  end
@@ -554,21 +581,22 @@ module Aspera
554
581
 
555
582
  def execute_application_action
556
583
  apps_info = aoc_api.read('admin/apps')
557
- all_app_types = apps_info.map{ |i| i['app_type'].to_sym}
584
+ # List of allowed symbols for app type
585
+ all_app_syms = apps_info.map{ |i| i['app_type'].to_sym}
558
586
  command_apps = options.get_next_command(%i[types settings instance membership])
559
587
  case command_apps
560
588
  when :types
561
- return Main.result_object_list(apps_info)
589
+ return Result::ObjectList.new(apps_info)
562
590
  when :settings
563
- app_type = options.get_next_command(all_app_types)
591
+ app_type = options.get_next_command(all_app_syms)
564
592
  cmd_path = "/apps/#{app_type}/settings"
565
593
  command_app_settings = options.get_next_command(Operations::SINGLETON)
566
594
  case command_app_settings
567
595
  when :show
568
- return Main.result_single_object(aoc_api.read(cmd_path))
596
+ return Result::SingleObject.new(aoc_api.read(cmd_path))
569
597
  when :modify
570
598
  aoc_api.update(cmd_path, options.get_next_argument('properties', validation: Hash))
571
- return Main.result_status('modified')
599
+ return Result::Status.new('modified')
572
600
  end
573
601
  when :instance
574
602
  list_default_query = {workspace_id: aoc_api.workspace_info[:id]}
@@ -576,17 +604,17 @@ module Aspera
576
604
  command_app_instances = options.get_next_command(%i[list] + Operations::SINGLETON)
577
605
  resource_path = 'admin/apps_new'
578
606
  if Operations::SINGLETON.include?(command_app_instances)
579
- app_type = options.get_next_command(all_app_types)
607
+ app_type = options.get_next_command(all_app_syms)
580
608
  resource_path = "#{resource_path}/#{app_type}/#{options.instance_identifier(description: "#{app_type} identifier")}"
581
609
  end
582
610
  case command_app_instances
583
611
  when :list
584
612
  return result_list(resource_path, fields: list_default_fields, default_query: list_default_query)
585
613
  when :show
586
- return Main.result_single_object(aoc_api.read(resource_path, query_read_delete))
614
+ return Result::SingleObject.new(aoc_api.read(resource_path, query_read_delete))
587
615
  when :modify
588
616
  aoc_api.update(resource_path, options.get_next_argument('properties', validation: Hash))
589
- return Main.result_status('modified')
617
+ return Result::Status.new('modified')
590
618
  end
591
619
  when :membership
592
620
  resource_path = 'apps/app_memberships'
@@ -596,13 +624,16 @@ module Aspera
596
624
  when :list
597
625
  return result_list(resource_path)
598
626
  when :delete
599
- aoc_api.delete("#{resource_path}}")
600
- return Main.result_status('deleted')
627
+ aoc_api.delete(resource_path)
628
+ return Result::Status.new('deleted')
601
629
  when :show
602
- return Main.result_single_object(aoc_api.read(resource_path, query_read_delete))
630
+ return Result::SingleObject.new(aoc_api.read(resource_path, query_read_delete))
603
631
  when :create
604
- aoc_api.update(resource_path, options.get_next_argument('membership properties', validation: Hash))
605
- return Main.result_status('modified')
632
+ data = options.get_next_argument('membership properties', validation: Hash)
633
+ app_type = data.delete('app_type')
634
+ Aspera.assert_type(app_type, String){'app_type'}
635
+ Aspera.assert_values(app_type.to_sym, all_app_syms){'app_type'}
636
+ return Result::SingleObject.new(aoc_api.create("apps/#{app_type}/app_memberships", data))
606
637
  end
607
638
  end
608
639
  end
@@ -615,7 +646,7 @@ module Aspera
615
646
  command_admin = options.get_next_command(ADMIN_ACTIONS)
616
647
  case command_admin
617
648
  when :bearer_token
618
- return Main.result_text(aoc_api.oauth.authorization)
649
+ return Result::Text.new(aoc_api.oauth.authorization)
619
650
  when *ADMIN_OBJECTS
620
651
  return execute_resource_action(command_admin)
621
652
  when :application
@@ -687,7 +718,7 @@ module Aspera
687
718
  GRAPHQL
688
719
  # cspell:enable
689
720
  result = bss_graphql.create(nil, {query: graphql_query, variables: {organization_id: org['id']}})['data']
690
- return Main.result_single_object(result['aoc']['bssSubscription'])
721
+ return Result::SingleObject.new(result['aoc']['bssSubscription'])
691
722
  when :usage
692
723
  # cspell:disable
693
724
  graphql_query = <<-GRAPHQL
@@ -738,7 +769,7 @@ module Aspera
738
769
  }
739
770
  }
740
771
  )['data']
741
- return Main.result_single_object(result['aoc'])
772
+ return Result::SingleObject.new(result['aoc'])
742
773
  end
743
774
  when :ats
744
775
  ats_api = Rest.new(**aoc_api.params.deep_merge({
@@ -756,7 +787,7 @@ module Aspera
756
787
  when :application_events
757
788
  event_type = command_analytics.to_s
758
789
  events = analytics_api.read("organizations/#{aoc_api.current_user_info['organization_id']}/#{event_type}")[event_type]
759
- return Main.result_object_list(events)
790
+ return Result::ObjectList.new(events)
760
791
  when :transfers
761
792
  event_type = command_analytics.to_s
762
793
  event_resource_type = options.get_next_argument('resource', accept_list: %i[organizations users nodes])
@@ -795,7 +826,7 @@ module Aspera
795
826
  config.send_email_template(values: {ev: tr_event})
796
827
  end
797
828
  end
798
- return Main.result_object_list(events)
829
+ return Result::ObjectList.new(events)
799
830
  when :files
800
831
  event_type = command_analytics.to_s
801
832
  event_resource_type = options.get_next_argument('resource', accept_list: %i[organizations users nodes])
@@ -811,7 +842,7 @@ module Aspera
811
842
  filter = query_read_delete(default: {})
812
843
  filter['limit'] ||= 100
813
844
  events = analytics_api.read("#{event_resource_type}/#{event_resource_id}/transfers/#{event_uuid}/#{event_type}", filter)[event_type]
814
- return Main.result_object_list(events)
845
+ return Result::ObjectList.new(events)
815
846
  end
816
847
  when :usage_reports
817
848
  return result_list('usage_reports', base_query: workspace_id_hash)
@@ -825,7 +856,10 @@ module Aspera
825
856
  # - a resource id, e.g. `scQ7uXPbvQ`
826
857
  # - a short URL path, e.g. `dxyRpT9`
827
858
  # @param shared_data [Hash] Information for shared data: dropbox_id+name or file_id+node_id
828
- # @param &perm_block [Proc] Optional: create/modify/delete permissions on node
859
+ # @param shared_data [Hash] Shared data for the short link
860
+ # @yieldparam operation [Symbol] Operation type (:create, :update, :delete)
861
+ # @yieldparam resource_id [String] Resource ID for permission management
862
+ # @yieldparam access_levels [Object] Access levels for permissions
829
863
  def short_link_command(**shared_data, &perm_block)
830
864
  link_type = options.get_next_argument('link access (public or private)', accept_list: %i[public private])
831
865
  if shared_data.keys.sort == %i[dropbox_id name]
@@ -873,7 +907,7 @@ module Aspera
873
907
  result_create_short_link = aoc_api.create('short_links', create_payload)
874
908
  # Creation: perm_block: permission on node
875
909
  yield(:create, result_create_short_link['resource_id'], access_levels) if block_given? && link_type.eql?(:public)
876
- return Main.result_single_object(result_create_short_link)
910
+ return Result::SingleObject.new(result_create_short_link)
877
911
  when :delete, :list, :show, :modify
878
912
  workspace_id_hash(shared_data)
879
913
  query = if link_type.eql?(:private)
@@ -906,14 +940,14 @@ module Aspera
906
940
  edit_access: true,
907
941
  json_query: shared_data.to_json
908
942
  })
909
- return Main.result_status('deleted')
943
+ return Result::Status.new('deleted')
910
944
  when :list
911
- return Main.result_object_list(short_list[:items], fields: Formatter.all_but('data'), total: short_list[:total])
945
+ return Result::ObjectList.new(short_list[:items], fields: Formatter.all_but('data'), total: short_list[:total])
912
946
  when :show
913
947
  one_id = options.instance_identifier(description: 'short link id')
914
948
  found = short_list[:items].find{ |item| item['id'].eql?(one_id)}
915
949
  raise BadIdentifier.new('Short link', one_id) if found.nil?
916
- return Main.result_single_object(found, fields: Formatter.all_but('data'))
950
+ return Result::SingleObject.new(found, fields: Formatter.all_but('data'))
917
951
  when :modify
918
952
  one_id = options.instance_identifier(description: 'short link id')
919
953
  node_file = shared_data.slice(:node_id, :file_id)
@@ -941,7 +975,7 @@ module Aspera
941
975
  end
942
976
  modify_payload.deep_merge!(custom_data)
943
977
  aoc_api.update("short_links/#{one_id}", modify_payload)
944
- return Main.result_status('modified')
978
+ return Result::Status.new('modified')
945
979
  end
946
980
  else Aspera.error_unexpected_value(command)
947
981
  end
@@ -985,46 +1019,48 @@ module Aspera
985
1019
  when :reminder
986
1020
  # send an email reminder with list of orgs
987
1021
  user_email = options.get_option(:username, mandatory: true)
988
- Rest.new(base_url: "#{Api::AoC.api_base_url}/#{Api::AoC::API_V1}").create('organization_reminders', {email: user_email})
989
- return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
1022
+ no_auth_api = Api::AoC.new(url: options.get_option(:url), auth: :none)
1023
+ no_auth_api.create('organization_reminders', {email: user_email})
1024
+ return Result::Status.new("List of organizations user is member of, has been sent by e-mail to #{user_email}")
990
1025
  when :servers
991
- return Main.result_object_list(Rest.new(base_url: "#{Api::AoC.api_base_url}/#{Api::AoC::API_V1}").read('servers'))
1026
+ no_auth_api = Api::AoC.new(url: options.get_option(:url), auth: :none)
1027
+ return Result::ObjectList.new(no_auth_api.read('servers'))
992
1028
  when :bearer_token
993
- return Main.result_text(aoc_api.oauth.authorization)
1029
+ return Result::Text.new(aoc_api.oauth.authorization)
994
1030
  when :organization
995
- return Main.result_single_object(aoc_api.read('organization'))
1031
+ return Result::SingleObject.new(aoc_api.read('organization'))
996
1032
  when :tier_restrictions
997
- return Main.result_single_object(aoc_api.read('tier_restrictions'))
1033
+ return Result::SingleObject.new(aoc_api.read('tier_restrictions'))
998
1034
  when :user
999
- user_cmd = options.get_next_command(%i[workspaces profile preferences notifications contacts])
1035
+ user_cmd = options.get_next_command(%i[workspaces profile preferences notifications contacts settings])
1000
1036
  case user_cmd
1001
1037
  when :contacts
1002
1038
  return execute_resource_action(:contact)
1003
- # when :settings
1004
- # return Main.result_object_list(aoc_api.read('client_settings/'))
1039
+ when :settings
1040
+ return entity_execute(api: aoc_api, entity: 'client_settings')
1005
1041
  when :workspaces
1006
1042
  case options.get_next_command(%i[list current])
1007
1043
  when :list
1008
1044
  return result_list('workspaces', fields: %w[id name])
1009
1045
  when :current
1010
- return Main.result_single_object(aoc_api.workspace_info)
1046
+ return Result::SingleObject.new(aoc_api.workspace_info)
1011
1047
  end
1012
1048
  when :profile
1013
1049
  case options.get_next_command(%i[show modify])
1014
1050
  when :show
1015
- return Main.result_single_object(aoc_api.current_user_info(exception: true))
1051
+ return Result::SingleObject.new(aoc_api.current_user_info(exception: true))
1016
1052
  when :modify
1017
1053
  aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}", options.get_next_argument('properties', validation: Hash))
1018
- return Main.result_status('modified')
1054
+ return Result::Status.new('modified')
1019
1055
  end
1020
1056
  when :preferences, :notifications
1021
1057
  user_preferences_res = "users/#{aoc_api.current_user_info(exception: true)['id']}/#{user_cmd.eql?(:preferences) ? 'user_interaction_preferences' : 'notification_preferences'}"
1022
1058
  case options.get_next_command(%i[show modify])
1023
1059
  when :show
1024
- return Main.result_single_object(aoc_api.read(user_preferences_res))
1060
+ return Result::SingleObject.new(aoc_api.read(user_preferences_res))
1025
1061
  when :modify
1026
1062
  aoc_api.update(user_preferences_res, options.get_next_argument('properties', validation: Hash))
1027
- return Main.result_status('modified')
1063
+ return Result::Status.new('modified')
1028
1064
  end
1029
1065
  end
1030
1066
  when :packages
@@ -1037,13 +1073,13 @@ module Aspera
1037
1073
  workspace_id_hash(default_query, string: true)
1038
1074
  return result_list('dropbox_memberships', fields: %w[dropbox_id dropbox.name], default_query: default_query)
1039
1075
  when :show
1040
- return Main.result_single_object(aoc_api.read(get_resource_path_from_args('dropboxes')))
1076
+ return Result::SingleObject.new(aoc_api.read(get_resource_path_from_args('dropboxes')))
1041
1077
  when :short_link
1042
1078
  # TODO: check name
1043
1079
  return short_link_command(dropbox_id: get_resource_id_from_args('dropboxes'), name: '')
1044
1080
  end
1045
1081
  when :send
1046
- package_data = value_create_modify(command: package_command)
1082
+ package_data = value_create_modify(command: package_command, schema: Schema::Registry.req_body(Schema::Registry::AOC, 'packages.post'))
1047
1083
  new_user_option = options.get_option(:new_user_option)
1048
1084
  option_validate = options.get_option(:validate_metadata)
1049
1085
  # Works for both normal user auth and link auth.
@@ -1058,9 +1094,9 @@ module Aspera
1058
1094
  package_data['encryption_at_rest'] = true if transfer.user_transfer_spec['content_protection'].eql?('encrypt')
1059
1095
  # transfer may raise an error
1060
1096
  created_package = aoc_api.create_package_simple(package_data, option_validate, new_user_option)
1061
- Main.result_transfer(transfer.start(created_package[:spec], rest_token: created_package[:node]))
1097
+ Runner.result_transfer(transfer.start(created_package[:spec], rest_token: created_package[:node]))
1062
1098
  # return all info on package (especially package id)
1063
- return Main.result_single_object(created_package[:info])
1099
+ return Result::SingleObject.new(created_package[:info])
1064
1100
  when :receive
1065
1101
  ids_to_download = nil
1066
1102
  if !aoc_api.public_link.nil?
@@ -1074,10 +1110,10 @@ module Aspera
1074
1110
  case ids_to_download
1075
1111
  when SpecialValues::INIT
1076
1112
  all_packages = list_all_packages_with_query[:items]
1077
- Aspera.assert(skip_ids_persistency){'INIT requires option once_only'}
1113
+ Aspera.assert(skip_ids_persistency, 'INIT requires option once_only')
1078
1114
  skip_ids_persistency.data.clear.concat(all_packages.map{ |e| e['id']})
1079
1115
  skip_ids_persistency.save
1080
- return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
1116
+ return Result::Status.new("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
1081
1117
  when SpecialValues::ALL
1082
1118
  all_packages = list_all_packages_with_query[:items]
1083
1119
  # remove from list the ones already downloaded
@@ -1115,25 +1151,25 @@ module Aspera
1115
1151
  rest_token: package_node_api
1116
1152
  )
1117
1153
  File.write(File.join(dest_folder, "#{package_id}.info.json"), package_info.to_json) if save_metadata
1118
- result_transfer.push({'package' => package_id, Main::STATUS_FIELD => statuses})
1154
+ result_transfer.push({'package' => package_id, Runner::STATUS_FIELD => statuses})
1119
1155
  # update skip list only if all transfer sessions completed
1120
1156
  if skip_ids_persistency && TransferAgent.session_status(statuses).eql?(:success)
1121
1157
  skip_ids_persistency.data.push(package_id)
1122
1158
  skip_ids_persistency.save
1123
1159
  end
1124
1160
  end
1125
- return Main.result_transfer_multiple(result_transfer)
1161
+ return Runner.result_transfer_multiple(result_transfer)
1126
1162
  when :show
1127
1163
  package_id = options.instance_identifier
1128
1164
  package_info = aoc_api.read("packages/#{package_id}")
1129
- return Main.result_single_object(package_info)
1165
+ return Result::SingleObject.new(package_info)
1130
1166
  when :list
1131
1167
  result = list_all_packages_with_query
1132
1168
  skip_ids_persistency = package_persistency
1133
1169
  reject_packages_from_persistency(result[:items], skip_ids_persistency)
1134
1170
  display_fields = PACKAGE_LIST_DEFAULT_FIELDS
1135
1171
  display_fields += ['workspace_id'] if aoc_api.workspace_info[:id].nil?
1136
- return Main.result_object_list(result[:items], fields: display_fields, total: result[:total])
1172
+ return Result::ObjectList.new(result[:items], fields: display_fields, total: result[:total])
1137
1173
  when :delete
1138
1174
  return do_bulk_operation(command: package_command, values: options.instance_identifier) do |package_id|
1139
1175
  Aspera.assert_type(package_id, String, Integer){'identifier'}
@@ -1143,7 +1179,7 @@ module Aspera
1143
1179
  package_id = options.instance_identifier
1144
1180
  package_data = value_create_modify(command: package_command)
1145
1181
  aoc_api.update("packages/#{package_id}", package_data)
1146
- return Main.result_status('modified')
1182
+ return Result::Status.new('modified')
1147
1183
  when *Node::NODE4_READ_ACTIONS
1148
1184
  package_id = options.instance_identifier
1149
1185
  package_info = aoc_api.read("packages/#{package_id}")
@@ -1220,7 +1256,7 @@ module Aspera
1220
1256
  when :launch
1221
1257
  wf_id = options.instance_identifier
1222
1258
  data = automation_api.create("workflows/#{wf_id}/launch", {})
1223
- return Main.result_single_object(data)
1259
+ return Result::SingleObject.new(data)
1224
1260
  when :action
1225
1261
  # TODO: not complete
1226
1262
  wf_id = options.instance_identifier
@@ -1231,7 +1267,7 @@ module Aspera
1231
1267
  action = automation_api.create('actions', {'step_id' => step['id'], 'type' => 'manual'})
1232
1268
  automation_api.update("steps/#{step['id']}", {'action_order' => [action['id']]})
1233
1269
  wf = automation_api.read("workflows/#{wf_id}")
1234
- return Main.result_single_object(wf)
1270
+ return Result::SingleObject.new(wf)
1235
1271
  end
1236
1272
  end
1237
1273
  when :admin
@@ -1241,10 +1277,10 @@ module Aspera
1241
1277
  parameters = value_create_modify(command: command, default: {}).symbolize_keys
1242
1278
  uri = URI.parse(parameters.delete(:url){WebServerSimple::DEFAULT_URL})
1243
1279
  server = WebServerSimple.new(uri, **parameters.slice(*WebServerSimple::PARAMS))
1244
- Aspera.assert(parameters.except(*WebServerSimple::PARAMS).empty?)
1280
+ Aspera.assert(parameters.except(*WebServerSimple::PARAMS).empty?){"unexpected parameters: #{parameters.except(*WebServerSimple::PARAMS).keys}"}
1245
1281
  server.mount(uri.path, Faspex4GWServlet, aoc_api, aoc_api.workspace_info[:id])
1246
1282
  server.start
1247
- return Main.result_status('Gateway terminated')
1283
+ return Result::Status.new('Gateway terminated')
1248
1284
  else Aspera.error_unreachable_line
1249
1285
  end
1250
1286
  Aspera.error_unreachable_line