aspera-cli 4.16.0 → 4.17.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 (97) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +50 -19
  4. data/CONTRIBUTING.md +3 -1
  5. data/README.md +965 -793
  6. data/bin/asession +29 -21
  7. data/lib/aspera/{fasp/agent_alpha.rb → agent/alpha.rb} +26 -25
  8. data/lib/aspera/{fasp/agent_base.rb → agent/base.rb} +15 -12
  9. data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
  10. data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +49 -53
  11. data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +20 -19
  12. data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +20 -33
  13. data/lib/aspera/{fasp/agent_trsdk.rb → agent/trsdk.rb} +11 -11
  14. data/lib/aspera/api/aoc.rb +586 -0
  15. data/lib/aspera/api/ats.rb +46 -0
  16. data/lib/aspera/api/cos_node.rb +95 -0
  17. data/lib/aspera/api/node.rb +344 -0
  18. data/lib/aspera/ascmd.rb +46 -10
  19. data/lib/aspera/{fasp → ascp}/installation.rb +5 -5
  20. data/lib/aspera/{fasp → ascp}/management.rb +3 -8
  21. data/lib/aspera/{fasp → ascp}/products.rb +1 -1
  22. data/lib/aspera/assert.rb +30 -30
  23. data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
  24. data/lib/aspera/cli/extended_value.rb +1 -1
  25. data/lib/aspera/cli/formatter.rb +13 -13
  26. data/lib/aspera/cli/hints.rb +5 -5
  27. data/lib/aspera/cli/main.rb +35 -28
  28. data/lib/aspera/cli/manager.rb +25 -24
  29. data/lib/aspera/cli/plugin.rb +22 -15
  30. data/lib/aspera/cli/plugin_factory.rb +61 -0
  31. data/lib/aspera/cli/plugins/alee.rb +7 -7
  32. data/lib/aspera/cli/plugins/aoc.rb +83 -77
  33. data/lib/aspera/cli/plugins/ats.rb +32 -33
  34. data/lib/aspera/cli/plugins/bss.rb +3 -4
  35. data/lib/aspera/cli/plugins/config.rb +169 -186
  36. data/lib/aspera/cli/plugins/console.rb +8 -6
  37. data/lib/aspera/cli/plugins/cos.rb +19 -18
  38. data/lib/aspera/cli/plugins/faspex.rb +61 -54
  39. data/lib/aspera/cli/plugins/faspex5.rb +150 -103
  40. data/lib/aspera/cli/plugins/node.rb +68 -73
  41. data/lib/aspera/cli/plugins/orchestrator.rb +34 -44
  42. data/lib/aspera/cli/plugins/preview.rb +31 -31
  43. data/lib/aspera/cli/plugins/server.rb +31 -33
  44. data/lib/aspera/cli/plugins/shares.rb +13 -11
  45. data/lib/aspera/cli/sync_actions.rb +8 -8
  46. data/lib/aspera/cli/transfer_agent.rb +32 -19
  47. data/lib/aspera/cli/transfer_progress.rb +1 -1
  48. data/lib/aspera/cli/version.rb +1 -1
  49. data/lib/aspera/colors.rb +5 -0
  50. data/lib/aspera/command_line_builder.rb +14 -14
  51. data/lib/aspera/coverage.rb +1 -2
  52. data/lib/aspera/data_repository.rb +1 -1
  53. data/lib/aspera/environment.rb +2 -3
  54. data/lib/aspera/faspex_gw.rb +5 -6
  55. data/lib/aspera/faspex_postproc.rb +1 -1
  56. data/lib/aspera/id_generator.rb +2 -2
  57. data/lib/aspera/json_rpc.rb +5 -5
  58. data/lib/aspera/keychain/encrypted_hash.rb +6 -6
  59. data/lib/aspera/keychain/macos_security.rb +27 -22
  60. data/lib/aspera/log.rb +2 -2
  61. data/lib/aspera/nagios.rb +3 -3
  62. data/lib/aspera/node_simulator.rb +5 -6
  63. data/lib/aspera/oauth/base.rb +143 -0
  64. data/lib/aspera/oauth/factory.rb +124 -0
  65. data/lib/aspera/oauth/generic.rb +34 -0
  66. data/lib/aspera/oauth/jwt.rb +51 -0
  67. data/lib/aspera/oauth/url_json.rb +31 -0
  68. data/lib/aspera/oauth/web.rb +50 -0
  69. data/lib/aspera/oauth.rb +5 -331
  70. data/lib/aspera/open_application.rb +7 -7
  71. data/lib/aspera/persistency_action_once.rb +4 -4
  72. data/lib/aspera/persistency_folder.rb +2 -2
  73. data/lib/aspera/preview/generator.rb +5 -5
  74. data/lib/aspera/preview/terminal.rb +3 -2
  75. data/lib/aspera/preview/utils.rb +3 -3
  76. data/lib/aspera/proxy_auto_config.rb +4 -4
  77. data/lib/aspera/rest.rb +175 -144
  78. data/lib/aspera/rest_errors_aspera.rb +3 -3
  79. data/lib/aspera/resumer.rb +77 -0
  80. data/lib/aspera/ssh.rb +6 -1
  81. data/lib/aspera/{fasp → transfer}/error.rb +3 -3
  82. data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
  83. data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
  84. data/lib/aspera/{fasp → transfer}/parameters.rb +58 -89
  85. data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +18 -16
  86. data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
  87. data/lib/aspera/{fasp → transfer}/sync.rb +32 -32
  88. data/lib/aspera/{fasp → transfer}/uri.rb +9 -8
  89. data/lib/aspera/web_server_simple.rb +11 -3
  90. data.tar.gz.sig +0 -0
  91. metadata +36 -63
  92. metadata.gz.sig +0 -0
  93. data/lib/aspera/aoc.rb +0 -601
  94. data/lib/aspera/ats_api.rb +0 -47
  95. data/lib/aspera/cos_node.rb +0 -94
  96. data/lib/aspera/fasp/resume_policy.rb +0 -79
  97. data/lib/aspera/node.rb +0 -339
@@ -19,6 +19,7 @@ module Aspera
19
19
  MAX_PAGES = 'pmax'
20
20
  # special identifier format: look for this name to find where supported
21
21
  REGEX_LOOKUP_ID_BY_FIELD = /^%([^:]+):(.*)$/.freeze
22
+ INIT_PARAMS = %i[options transfer config formatter persistency only_manual].freeze
22
23
 
23
24
  class << self
24
25
  def declare_generic_options(options)
@@ -33,12 +34,18 @@ module Aspera
33
34
  end
34
35
  end
35
36
 
36
- def initialize(env)
37
- assert_type(env, Hash)
38
- @agents = env
37
+ attr_accessor(*INIT_PARAMS)
38
+
39
+ def initialize(options:, transfer:, config:, formatter:, persistency:, only_manual:)
40
+ @options = options
41
+ @transfer = transfer
42
+ @config = config
43
+ @formatter = formatter
44
+ @persistency = persistency
45
+ @only_manual = only_manual
39
46
  # check presence in descendant of mandatory method and constant
40
- assert(respond_to?(:execute_action)){"Missing method 'execute_action' in #{self.class}"}
41
- assert(self.class.constants.include?(:ACTIONS)){'ACTIONS shall be redefined by subclass'}
47
+ Aspera.assert(respond_to?(:execute_action)){"Missing method 'execute_action' in #{self.class}"}
48
+ Aspera.assert(self.class.constants.include?(:ACTIONS)){'ACTIONS shall be redefined by subclass'}
42
49
  # manual header for all plugins
43
50
  options.parser.separator('')
44
51
  options.parser.separator("COMMAND: #{self.class.name.split('::').last.downcase}")
@@ -46,6 +53,11 @@ module Aspera
46
53
  options.parser.separator('OPTIONS:')
47
54
  end
48
55
 
56
+ def init_params
57
+ # return a hash of instance variables
58
+ INIT_PARAMS.map{|p| [p, instance_variable_get("@#{p}".to_sym)]}.to_h
59
+ end
60
+
49
61
  # must be called AFTER the instance action, ... folder browse <call instance_identifier>
50
62
  # @param description [String] description of the identifier
51
63
  # @param as_option [Symbol] option name to use if identifier is an option
@@ -76,7 +88,7 @@ module Aspera
76
88
  # @param id_result [String] key in result hash to use as identifier
77
89
  # @param fields [Array] fields to display
78
90
  def do_bulk_operation(command:, descr:, values: Hash, id_result: 'id', fields: :default)
79
- assert(block_given?){'missing block'}
91
+ Aspera.assert(block_given?){'missing block'}
80
92
  is_bulk = options.get_option(:bulk)
81
93
  case values
82
94
  when :identifier
@@ -238,23 +250,18 @@ module Aspera
238
250
  value = default if value.nil?
239
251
  unless type.nil?
240
252
  type = [type] unless type.is_a?(Array)
241
- assert(type.all?(Class)){"check types must be a Class, not #{type.map(&:class).join(',')}"}
253
+ Aspera.assert(type.all?(Class)){"check types must be a Class, not #{type.map(&:class).join(',')}"}
242
254
  if bulk
243
- assert_type(value, Array, exception_class: Cli::BadArgument)
255
+ Aspera.assert_type(value, Array, exception_class: Cli::BadArgument)
244
256
  value.each do |v|
245
- assert_values(v.class, type, exception_class: Cli::BadArgument)
257
+ Aspera.assert_values(v.class, type, exception_class: Cli::BadArgument)
246
258
  end
247
259
  else
248
- assert_values(value.class, type, exception_class: Cli::BadArgument)
260
+ Aspera.assert_values(value.class, type, exception_class: Cli::BadArgument)
249
261
  end
250
262
  end
251
263
  return value
252
264
  end
253
-
254
- # shortcuts helpers for plugin environment
255
- %i[options transfer config formatter persistency].each do |name|
256
- define_method(name){@agents[name]}
257
- end
258
265
  end # Plugin
259
266
  end # Cli
260
267
  end # Aspera
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ module Aspera
5
+ module Cli
6
+ # option is retrieved from another object using accessor
7
+ class PluginFactory
8
+ include Singleton
9
+ attr_reader :lookup_folders, :plugins
10
+
11
+ RUBY_FILE_EXT = '.rb'
12
+ PLUGINS_MODULE = 'Plugins'
13
+ private_constant :RUBY_FILE_EXT
14
+ class << self
15
+ # instantiate a plugin
16
+ # plugins must be Capitalized
17
+ def plugin_class(plugin_name_sym)
18
+ # Module.nesting[2] is Cli::Plugins
19
+ return Object.const_get("#{Module.nesting[2]}::#{PLUGINS_MODULE}::#{plugin_name_sym.to_s.capitalize}")
20
+ end
21
+ end
22
+
23
+ def initialize
24
+ @lookup_folders = []
25
+ @plugins = {}
26
+ end
27
+
28
+ def add_plugin_info(path)
29
+ raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
30
+ plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
31
+ req = path.sub(/#{RUBY_FILE_EXT}$/o, '')
32
+ if @plugins.key?(plugin_symbol)
33
+ Log.log.warn{"skipping plugin already registered: #{plugin_symbol}"}
34
+ return
35
+ end
36
+ @plugins[plugin_symbol] = {source: path, require_stanza: req}
37
+ end
38
+
39
+ def add_lookup_folder(folder)
40
+ @lookup_folders.unshift(folder)
41
+ end
42
+
43
+ # find plugins in defined paths
44
+ def add_plugins_from_lookup_folders
45
+ @lookup_folders.each do |folder|
46
+ next unless File.directory?(folder)
47
+ # TODO: add gem root to load path ? and require short folder ?
48
+ # $LOAD_PATH.push(folder) if i[:add_path]
49
+ Dir.entries(folder).select{|file|file.end_with?(RUBY_FILE_EXT)}.each do |source|
50
+ add_plugin_info(File.join(folder, source))
51
+ end
52
+ end
53
+ end
54
+
55
+ def create(plugin_name_sym, **args)
56
+ # TODO: check that ancestor is Plugin?
57
+ self.class.plugin_class(plugin_name_sym).new(**args)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'aspera/aoc'
3
+ require 'aspera/api/aoc'
4
4
 
5
5
  module Aspera
6
6
  module Cli
7
7
  module Plugins
8
- class Alee < Aspera::Cli::BasicAuthPlugin
8
+ class Alee < Cli::BasicAuthPlugin
9
9
  ACTIONS = %i[entitlement].freeze
10
10
 
11
11
  def execute_action
@@ -14,11 +14,11 @@ module Aspera
14
14
  when :entitlement
15
15
  entitlement_id = options.get_option(:username, mandatory: true)
16
16
  customer_id = options.get_option(:password, mandatory: true)
17
- api_metering = AoC.metering_api(entitlement_id, customer_id)
17
+ api_metering = Api::AoC.metering_api(entitlement_id, customer_id)
18
18
  return {type: :single_object, data: api_metering.read('entitlement')[:data]}
19
19
  end
20
20
  end
21
- end # Aspera
22
- end # Plugins
23
- end # Cli
24
- end # Aspera
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,10 +4,10 @@ require 'aspera/cli/plugins/node'
4
4
  require 'aspera/cli/plugins/ats'
5
5
  require 'aspera/cli/basic_auth_plugin'
6
6
  require 'aspera/cli/transfer_agent'
7
- require 'aspera/fasp/agent_node'
8
- require 'aspera/fasp/transfer_spec'
9
- require 'aspera/aoc'
10
- require 'aspera/node'
7
+ require 'aspera/agent/node'
8
+ require 'aspera/transfer/spec'
9
+ require 'aspera/api/aoc'
10
+ require 'aspera/api/node'
11
11
  require 'aspera/persistency_action_once'
12
12
  require 'aspera/id_generator'
13
13
  require 'aspera/assert'
@@ -17,11 +17,13 @@ require 'date'
17
17
  module Aspera
18
18
  module Cli
19
19
  module Plugins
20
- class Aoc < Aspera::Cli::BasicAuthPlugin
20
+ class Aoc < Cli::BasicAuthPlugin
21
21
  AOC_PATH_API_CLIENTS = 'admin/api-clients'
22
22
  # default redirect for AoC web auth
23
- DEFAULT_REDIRECT = 'http://localhost:12345'
24
- private_constant :AOC_PATH_API_CLIENTS, :DEFAULT_REDIRECT
23
+ REDIRECT_LOCALHOST = 'http://localhost:12345'
24
+ # OAuth methods supported
25
+ STD_AUTH_TYPES = %i[web jwt].freeze
26
+ private_constant :AOC_PATH_API_CLIENTS, :REDIRECT_LOCALHOST, :STD_AUTH_TYPES
25
27
  class << self
26
28
  def application_name
27
29
  'Aspera on Cloud'
@@ -31,13 +33,13 @@ module Aspera
31
33
  # no protocol ?
32
34
  base_url = "https://#{base_url}" unless base_url.match?(%r{^[a-z]{1,6}://})
33
35
  # only org provided ?
34
- base_url = "#{base_url}.#{Aspera::AoC::PROD_DOMAIN}" unless base_url.include?('.')
36
+ base_url = "#{base_url}.#{Api::AoC::PROD_DOMAIN}" unless base_url.include?('.')
35
37
  # AoC is only https
36
38
  return nil unless base_url.start_with?('https://')
37
- result = Rest.new({base_url: base_url, redirect_max: 10}).read('')
39
+ result = Rest.new(base_url: base_url, redirect_max: 10).read('')
38
40
  # Any AoC is on this domain
39
- return nil unless result[:http].uri.host.end_with?(Aspera::AoC::PROD_DOMAIN)
40
- Log.log.debug{'AoC Main page: #{result[:http].body.include?(Aspera::AoC::PRODUCT_NAME)}'}
41
+ return nil unless result[:http].uri.host.end_with?(Api::AoC::PROD_DOMAIN)
42
+ Log.log.debug{"AoC Main page: #{result[:http].body.include?(Api::AoC::PRODUCT_NAME)}"}
41
43
  base_url = result[:http].uri.to_s if result[:http].uri.path.include?('/public')
42
44
  # either in standard domain, or product name in page
43
45
  return {
@@ -48,7 +50,7 @@ module Aspera
48
50
 
49
51
  def private_key_required?(url)
50
52
  # pub link do not need private key
51
- return AoC.link_info(url)[:token].nil?
53
+ return Api::AoC.link_info(url)[:token].nil?
52
54
  end
53
55
 
54
56
  # @param [Hash] env : options, formatter
@@ -61,9 +63,9 @@ module Aspera
61
63
  options.declare(:use_generic_client, 'Wizard: AoC: use global or org specific jwt client id', values: :bool, default: true)
62
64
  options.parse_options!
63
65
  instance_url = options.get_option(:url, mandatory: true)
64
- pub_link_info = AoC.link_info(instance_url)
66
+ pub_link_info = Api::AoC.link_info(instance_url)
65
67
  if !pub_link_info[:token].nil?
66
- pub_api = Rest.new({base_url: "https://#{URI.parse(pub_link_info[:url]).host}/api/v1"})
68
+ pub_api = Rest.new(base_url: "https://#{URI.parse(pub_link_info[:url]).host}/api/v1")
67
69
  pub_info = pub_api.read('env/url_token_check', {token: pub_link_info[:token]})[:data]
68
70
  preset_value = {
69
71
  link: instance_url
@@ -100,7 +102,7 @@ module Aspera
100
102
  formatter.display_status('Navigate to: 𓃑 → Admin → Integrations → API Clients')
101
103
  formatter.display_status('Check or create in integration:')
102
104
  formatter.display_status("- name: #{@info[:name]}")
103
- formatter.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
105
+ formatter.display_status("- redirect uri: #{REDIRECT_LOCALHOST}")
104
106
  formatter.display_status('- origin: localhost')
105
107
  formatter.display_status('Use the generated client id and secret in the following prompts.'.red)
106
108
  end
@@ -113,13 +115,14 @@ module Aspera
113
115
  formatter.display_status('We will use web authentication to bootstrap.')
114
116
  auto_set_pub_key = true
115
117
  auto_set_jwt = true
116
- aoc_api.oauth.generic_parameters[:grant_method] = :web
117
- aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
118
- aoc_api.oauth.specific_parameters[:redirect_uri] = DEFAULT_REDIRECT
118
+ raise 'TODO'
119
+ # aoc_api.oauth.grant_method = :web
120
+ # aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN
121
+ # aoc_api.oauth.specific_parameters[:redirect_uri] = REDIRECT_LOCALHOST
119
122
  end
120
123
  myself = object.aoc_api.read('self')[:data]
121
124
  if auto_set_pub_key
122
- assert(myself['public_key'].empty?, exception_class: Cli::Error){'Public key is already set in profile (use --override=yes)'} unless option_override
125
+ Aspera.assert(myself['public_key'].empty?, exception_class: Cli::Error){'Public key is already set in profile (use --override=yes)'} unless option_override
123
126
  formatter.display_status('Updating profile with the public key.')
124
127
  aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
125
128
  end
@@ -172,19 +175,19 @@ module Aspera
172
175
  'received' => true,
173
176
  'completed' => true}.freeze
174
177
 
175
- def initialize(env)
176
- super(env)
178
+ def initialize(**env)
179
+ super
177
180
  @cache_workspace_info = nil
178
181
  @cache_home_node_file = nil
179
182
  @cache_api_aoc = nil
180
- options.declare(:auth, 'OAuth type of authentication', values: Oauth::STD_AUTH_TYPES, default: :jwt)
183
+ options.declare(:auth, 'OAuth type of authentication', values: STD_AUTH_TYPES, default: :jwt)
181
184
  options.declare(:client_id, 'OAuth API client identifier')
182
185
  options.declare(:client_secret, 'OAuth API client secret')
183
- options.declare(:scope, 'OAuth scope for AoC API calls', default: AoC::SCOPE_FILES_USER)
186
+ options.declare(:scope, 'OAuth scope for AoC API calls', default: Api::AoC::SCOPE_FILES_USER)
184
187
  options.declare(:redirect_uri, 'OAuth API client redirect URI')
185
188
  options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
186
189
  options.declare(:passphrase, 'RSA private key passphrase')
187
- options.declare(:workspace, 'Name of workspace', types: [String, NilClass], default: Aspera::AoC::DEFAULT_WORKSPACE)
190
+ options.declare(:workspace, 'Name of workspace', types: [String, NilClass], default: Api::AoC::DEFAULT_WORKSPACE)
188
191
  options.declare(:new_user_option, 'New user creation option for unknown package recipients')
189
192
  options.declare(:validate_metadata, 'Validate shared inbox metadata', values: :bool, default: true)
190
193
  options.parse_options!
@@ -195,9 +198,9 @@ module Aspera
195
198
  OPTIONS_NEW = %i[url auth client_id client_secret scope redirect_uri private_key passphrase username password workspace].freeze
196
199
 
197
200
  def api_from_options(new_base_path)
198
- create_values = {subpath: new_base_path, secret_finder: @agents[:config]}
201
+ create_values = {subpath: new_base_path, secret_finder: config}
199
202
  # create an API object with the same options, but with a different subpath
200
- return Aspera::AoC.new(**OPTIONS_NEW.each_with_object(create_values) { |i, m|m[i] = options.get_option(i) unless options.get_option(i).nil?})
203
+ return Api::AoC.new(**OPTIONS_NEW.each_with_object(create_values) { |i, m|m[i] = options.get_option(i) unless options.get_option(i).nil?})
201
204
  rescue ArgumentError => e
202
205
  if (m = e.message.match(/missing keyword: :(.*)$/))
203
206
  raise Cli::Error, "Missing option: #{m[1]}"
@@ -206,7 +209,14 @@ module Aspera
206
209
  end
207
210
 
208
211
  def aoc_api
209
- @cache_api_aoc = api_from_options(AoC::API_V1) if @cache_api_aoc.nil?
212
+ if @cache_api_aoc.nil?
213
+ @cache_api_aoc = api_from_options(Api::AoC::API_V1)
214
+ organization = @cache_api_aoc.read('organization')[:data]
215
+ if organization['http_gateway_enabled'] && organization['http_gateway_server_url']
216
+ transfer.httpgw_url_cb = lambda { organization['http_gateway_server_url'] }
217
+ # @cache_api_aoc.current_user_info['connect_disabled']
218
+ end
219
+ end
210
220
  return @cache_api_aoc
211
221
  end
212
222
 
@@ -214,7 +224,7 @@ module Aspera
214
224
  # @return identifier
215
225
  def get_resource_id_from_args(resource_class_path)
216
226
  return instance_identifier do |field, value|
217
- assert(field.eql?('name'), exception_class: Cli::BadArgument){'only selection by name is supported'}
227
+ Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only selection by name is supported'}
218
228
  aoc_api.lookup_by_name(resource_class_path, value)['id']
219
229
  end
220
230
  end
@@ -226,8 +236,8 @@ module Aspera
226
236
  # Call block with same query using paging and response information
227
237
  # @return [Hash] {data: , total: }
228
238
  def api_call_paging(base_query={})
229
- assert_type(base_query, Hash){'query'}
230
- assert(block_given?)
239
+ Aspera.assert_type(base_query, Hash){'query'}
240
+ Aspera.assert(block_given?)
231
241
  # set default large page if user does not specify own parameters. AoC Caps to 1000 anyway
232
242
  base_query['per_page'] = 1000 unless base_query.key?('per_page')
233
243
  max_items = base_query.delete(MAX_ITEMS)
@@ -265,8 +275,8 @@ module Aspera
265
275
 
266
276
  # list all entities, given additional, default and user's queries
267
277
  def result_list(resource_class_path, fields: nil, base_query: {}, default_query: {})
268
- assert_type(base_query, Hash)
269
- assert_type(default_query, Hash)
278
+ Aspera.assert_type(base_query, Hash)
279
+ Aspera.assert_type(default_query, Hash)
270
280
  user_query = query_read_delete(default: default_query)
271
281
  # caller may add specific modifications or checks
272
282
  yield(user_query) if block_given?
@@ -277,11 +287,13 @@ module Aspera
277
287
  if query.key?('dropbox_name')
278
288
  # convenience: specify name instead of id
279
289
  raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
290
+ # TODO : craft a query that looks for dropbox only in current workspace
280
291
  query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query['dropbox_name'])['id']
281
292
  query.delete('dropbox_name')
282
293
  end
283
294
  query['workspace_id'] ||= aoc_api.context[:workspace_id] unless aoc_api.context[:workspace_id].eql?(:undefined)
284
- query['exclude_dropbox_packages'] = true unless query.key?('dropbox_id')
295
+ # by default show dropbox packages only for dropboxes
296
+ query['exclude_dropbox_packages'] = !query.key?('dropbox_id') unless query.key?('exclude_dropbox_packages')
285
297
  end
286
298
 
287
299
  NODE4_EXT_COMMANDS = %i[transfer].concat(Node::COMMANDS_GEN4).freeze
@@ -297,7 +309,7 @@ module Aspera
297
309
  scope: scope
298
310
  )
299
311
  file_id = top_node_api.read("access_keys/#{top_node_api.app_info[:node_info]['access_key']}")[:data]['root_file_id'] if file_id.nil?
300
- node_plugin = Node.new(@agents, api: top_node_api)
312
+ node_plugin = Node.new(**init_params, api: top_node_api)
301
313
  case command_repo
302
314
  when *Node::COMMANDS_GEN4
303
315
  return node_plugin.execute_command_gen4(command_repo, file_id)
@@ -309,20 +321,20 @@ module Aspera
309
321
  source_folder = options.get_next_argument('folder of source files', type: String)
310
322
  case push_pull
311
323
  when :push
312
- client_direction = Fasp::TransferSpec::DIRECTION_SEND
324
+ client_direction = Transfer::Spec::DIRECTION_SEND
313
325
  client_folder = source_folder
314
326
  server_folder = transfer.destination_folder(client_direction)
315
327
  when :pull
316
- client_direction = Fasp::TransferSpec::DIRECTION_RECEIVE
328
+ client_direction = Transfer::Spec::DIRECTION_RECEIVE
317
329
  client_folder = transfer.destination_folder(client_direction)
318
330
  server_folder = source_folder
319
- else error_unreachable_line
331
+ else Aspera.error_unreachable_line
320
332
  end
321
333
  client_apfid = top_node_api.resolve_api_fid(file_id, client_folder)
322
334
  server_apfid = top_node_api.resolve_api_fid(file_id, server_folder)
323
335
  # force node as transfer agent
324
- @agents[:transfer].agent_instance = Fasp::AgentNode.new({
325
- url: client_apfid[:api].params[:base_url],
336
+ transfer.agent_instance = Agent::Node.new({
337
+ url: client_apfid[:api].base_url,
326
338
  username: client_apfid[:api].app_info[:node_info]['access_key'],
327
339
  password: client_apfid[:api].oauth_token,
328
340
  root_id: client_apfid[:file_id]
@@ -337,14 +349,14 @@ module Aspera
337
349
  server_apfid[:file_id],
338
350
  client_direction,
339
351
  add_ts)))
340
- else error_unreachable_line
352
+ else Aspera.error_unreachable_line
341
353
  end # command_repo
342
- error_unreachable_line
354
+ Aspera.error_unreachable_line
343
355
  end # execute_nodegen4_command
344
356
 
345
357
  def execute_admin_action
346
358
  # upgrade scope to admin
347
- aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
359
+ aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN
348
360
  command_admin = options.get_next_command(%i[ats resource usage_reports analytics subscription auth_providers])
349
361
  case command_admin
350
362
  when :auth_providers
@@ -411,15 +423,15 @@ module Aspera
411
423
  result = bss_api.create('graphql', {'variables' => {'organization_id' => org['id']}, 'query' => graphql_query})[:data]['data']
412
424
  return {type: :single_object, data: result['aoc']['bssSubscription']}
413
425
  when :ats
414
- ats_api = Rest.new(aoc_api.params.deep_merge({
415
- base_url: "#{aoc_api.params[:base_url]}/admin/ats/pub/v1",
416
- auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
426
+ ats_api = Rest.new(**aoc_api.params.deep_merge({
427
+ base_url: "#{aoc_api.base_url}/admin/ats/pub/v1",
428
+ auth: {scope: Api::AoC::SCOPE_FILES_ADMIN_USER}
417
429
  }))
418
- return Ats.new(@agents).execute_action_gen(ats_api)
430
+ return Ats.new(**init_params).execute_action_gen(ats_api)
419
431
  when :analytics
420
- analytics_api = Rest.new(aoc_api.params.deep_merge({
421
- base_url: "#{aoc_api.params[:base_url].gsub('/api/v1', '')}/analytics/v2",
422
- auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
432
+ analytics_api = Rest.new(**aoc_api.params.deep_merge({
433
+ base_url: "#{aoc_api.base_url.gsub('/api/v1', '')}/analytics/v2",
434
+ auth: {scope: Api::AoC::SCOPE_FILES_ADMIN_USER}
423
435
  }))
424
436
  command_analytics = options.get_next_command(%i[application_events transfers])
425
437
  case command_analytics
@@ -435,14 +447,14 @@ module Aspera
435
447
  when :organizations then aoc_api.current_user_info['organization_id']
436
448
  when :users then aoc_api.current_user_info['id']
437
449
  when :nodes then aoc_api.current_user_info['id'] # TODO: consistent ? # rubocop:disable Lint/DuplicateBranch
438
- else error_unreachable_line
450
+ else Aspera.error_unreachable_line
439
451
  end
440
452
  filter = options.get_option(:query) || {}
441
453
  filter['limit'] ||= 100
442
454
  if options.get_option(:once_only, mandatory: true)
443
455
  saved_date = []
444
456
  start_date_persistency = PersistencyActionOnce.new(
445
- manager: @agents[:persistency],
457
+ manager: persistency,
446
458
  data: saved_date,
447
459
  id: IdGenerator.from_list([
448
460
  'aoc_ana_date',
@@ -549,7 +561,7 @@ module Aspera
549
561
  # init context
550
562
  aoc_api.context(:files)
551
563
  return execute_nodegen4_command(command_repo, res_id)
552
- else error_unexpected_value(command)
564
+ else Aspera.error_unexpected_value(command)
553
565
  end
554
566
  when :usage_reports
555
567
  return result_list('usage_reports', base_query: {workspace_id: aoc_api.context(:files)[:workspace_id]})
@@ -574,10 +586,10 @@ module Aspera
574
586
  when :reminder
575
587
  # send an email reminder with list of orgs
576
588
  user_email = options.get_option(:username, mandatory: true)
577
- Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders', {email: user_email})[:data]
589
+ Rest.new(base_url: "#{Api::AoC.api_base_url}/#{Api::AoC::API_V1}").create('organization_reminders', {email: user_email})[:data]
578
590
  return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
579
591
  when :servers
580
- return {type: :object_list, data: Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
592
+ return {type: :object_list, data: Rest.new(base_url: "#{Api::AoC.api_base_url}/#{Api::AoC::API_V1}").read('servers')[:data]}
581
593
  when :bearer_token
582
594
  return {type: :text, data: aoc_api.oauth_token}
583
595
  when :organization
@@ -659,7 +671,7 @@ module Aspera
659
671
  if options.get_option(:once_only, mandatory: true)
660
672
  # TODO: add query info to id
661
673
  skip_ids_persistency = PersistencyActionOnce.new(
662
- manager: @agents[:persistency],
674
+ manager: persistency,
663
675
  data: skip_ids_data,
664
676
  id: IdGenerator.from_list(
665
677
  ['aoc_recv',
@@ -670,12 +682,12 @@ module Aspera
670
682
  case ids_to_download
671
683
  when ExtendedValue::ALL, ExtendedValue::INIT
672
684
  query = query_read_delete(default: PACKAGE_RECEIVED_BASE_QUERY)
673
- assert_type(query, Hash){'query'}
685
+ Aspera.assert_type(query, Hash){'query'}
674
686
  resolve_dropbox_name_default_ws_id(query)
675
687
  # remove from list the ones already downloaded
676
688
  all_ids = api_read_all('packages', query)[:data].map{|e|e['id']}
677
689
  if ids_to_download.eql?(ExtendedValue::INIT)
678
- assert(skip_ids_persistency){'Only with option once_only'}
690
+ Aspera.assert(skip_ids_persistency){'Only with option once_only'}
679
691
  skip_ids_persistency.data.clear.concat(all_ids)
680
692
  skip_ids_persistency.save
681
693
  return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
@@ -690,7 +702,7 @@ module Aspera
690
702
  formatter.display_status("found #{ids_to_download.length} package(s).")
691
703
  ids_to_download.each do |package_id|
692
704
  package_info = aoc_api.read("packages/#{package_id}")[:data]
693
- formatter.display_status("downloading package: #{package_info['name']}")
705
+ formatter.display_status("downloading package: [#{package_info['id']}] #{package_info['name']}")
694
706
  package_node_api = aoc_api.node_api_from(
695
707
  node_id: package_info['node_id'],
696
708
  workspace_id: aoc_api.context[:workspace_id],
@@ -699,7 +711,7 @@ module Aspera
699
711
  statuses = transfer.start(
700
712
  package_node_api.transfer_spec_gen4(
701
713
  package_info['contents_file_id'],
702
- Fasp::TransferSpec::DIRECTION_RECEIVE,
714
+ Transfer::Spec::DIRECTION_RECEIVE,
703
715
  {'paths'=> [{'source' => '.'}]}),
704
716
  rest_token: package_node_api)
705
717
  result_transfer.push({'package' => package_id, Main::STATUS_FIELD => statuses})
@@ -722,19 +734,19 @@ module Aspera
722
734
  end
723
735
  when :delete
724
736
  return do_bulk_operation(command: package_command, descr: 'identifier', values: identifier) do |id|
725
- assert_values(id.class, [String, Integer]){'identifier'}
737
+ Aspera.assert_values(id.class, [String, Integer]){'identifier'}
726
738
  aoc_api.delete("packages/#{id}")[:data]
727
739
  end
728
740
  when *Node::NODE4_READ_ACTIONS
729
741
  package_id = instance_identifier
730
742
  package_info = aoc_api.read("packages/#{package_id}")[:data]
731
- return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['file_id'], scope: Aspera::Node::SCOPE_USER)
743
+ return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['file_id'], scope: Api::Node::SCOPE_USER)
732
744
  end
733
745
  when :files
734
746
  command_repo = options.get_next_command([:short_link].concat(NODE4_EXT_COMMANDS))
735
747
  case command_repo
736
748
  when *NODE4_EXT_COMMANDS
737
- return execute_nodegen4_command(command_repo, aoc_api.context[:home_node_id], file_id: aoc_api.context[:home_file_id], scope: Aspera::Node::SCOPE_USER)
749
+ return execute_nodegen4_command(command_repo, aoc_api.context[:home_node_id], file_id: aoc_api.context[:home_file_id], scope: Api::Node::SCOPE_USER)
738
750
  when :short_link
739
751
  link_type = options.get_next_argument('link type', expected: %i[public private])
740
752
  short_link_command = options.get_next_command(%i[create delete list])
@@ -752,7 +764,7 @@ module Aspera
752
764
  purpose = case link_type
753
765
  when :public then 'token_auth_redirection'
754
766
  when :private then 'shared_folder_auth_link'
755
- else error_unreachable_line
767
+ else Aspera.error_unreachable_line
756
768
  end
757
769
  case short_link_command
758
770
  when :delete
@@ -812,7 +824,7 @@ module Aspera
812
824
  if link_type.eql?(:public)
813
825
  # TODO: merge with node permissions ?
814
826
  # TODO: access level as arg
815
- access_levels = Aspera::Node::ACCESS_LEVELS # ['delete','list','mkdir','preview','read','rename','write']
827
+ access_levels = Api::Node::ACCESS_LEVELS # ['delete','list','mkdir','preview','read','rename','write']
816
828
  folder_name = File.basename(folder_dest)
817
829
  perm_data = {
818
830
  'file_id' => shared_apfid[:file_id],
@@ -841,9 +853,7 @@ module Aspera
841
853
  when :automation
842
854
  Log.log.warn('BETA: work under progress')
843
855
  # automation api is not in the same place
844
- automation_rest_params = aoc_api.params.clone
845
- automation_rest_params[:base_url].gsub!('/api/', '/automation/')
846
- automation_api = Rest.new(automation_rest_params)
856
+ automation_api = Rest.new(**aoc_api.params.merge(base_url: aoc_api.base_url.gsub('/api/', '/automation/')))
847
857
  command_automation = options.get_next_command(%i[workflows instances])
848
858
  case command_automation
849
859
  when :instances
@@ -878,19 +888,15 @@ module Aspera
878
888
  uri = URI.parse(url)
879
889
  server = WebServerSimple.new(uri)
880
890
  server.mount(uri.path, Faspex4GWServlet, aoc_api, aoc_api.context(:files)[:workspace_id])
881
- trap('INT') { server.shutdown }
882
- formatter.display_status("Faspex 4 gateway listening on #{url}")
883
- Log.log.info("Listening on #{url}")
884
- # this is blocking until server exits
885
891
  server.start
886
892
  return Main.result_status('Gateway terminated')
887
- else error_unreachable_line
893
+ else Aspera.error_unreachable_line
888
894
  end # action
889
- error_unreachable_line
895
+ Aspera.error_unreachable_line
890
896
  end
891
897
 
892
898
  private :execute_admin_action
893
- end # AoC
894
- end # Plugins
895
- end # Cli
896
- end # Aspera
899
+ end
900
+ end
901
+ end
902
+ end