aspera-cli 4.16.0 → 4.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +50 -19
- data/CONTRIBUTING.md +3 -1
- data/README.md +965 -793
- data/bin/asession +29 -21
- data/lib/aspera/{fasp/agent_alpha.rb → agent/alpha.rb} +26 -25
- data/lib/aspera/{fasp/agent_base.rb → agent/base.rb} +15 -12
- data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
- data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +49 -53
- data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +20 -19
- data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +20 -33
- data/lib/aspera/{fasp/agent_trsdk.rb → agent/trsdk.rb} +11 -11
- data/lib/aspera/api/aoc.rb +586 -0
- data/lib/aspera/api/ats.rb +46 -0
- data/lib/aspera/api/cos_node.rb +95 -0
- data/lib/aspera/api/node.rb +344 -0
- data/lib/aspera/ascmd.rb +46 -10
- data/lib/aspera/{fasp → ascp}/installation.rb +5 -5
- data/lib/aspera/{fasp → ascp}/management.rb +3 -8
- data/lib/aspera/{fasp → ascp}/products.rb +1 -1
- data/lib/aspera/assert.rb +30 -30
- data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
- data/lib/aspera/cli/extended_value.rb +1 -1
- data/lib/aspera/cli/formatter.rb +13 -13
- data/lib/aspera/cli/hints.rb +5 -5
- data/lib/aspera/cli/main.rb +35 -28
- data/lib/aspera/cli/manager.rb +25 -24
- data/lib/aspera/cli/plugin.rb +22 -15
- data/lib/aspera/cli/plugin_factory.rb +61 -0
- data/lib/aspera/cli/plugins/alee.rb +7 -7
- data/lib/aspera/cli/plugins/aoc.rb +83 -77
- data/lib/aspera/cli/plugins/ats.rb +32 -33
- data/lib/aspera/cli/plugins/bss.rb +3 -4
- data/lib/aspera/cli/plugins/config.rb +169 -186
- data/lib/aspera/cli/plugins/console.rb +8 -6
- data/lib/aspera/cli/plugins/cos.rb +19 -18
- data/lib/aspera/cli/plugins/faspex.rb +61 -54
- data/lib/aspera/cli/plugins/faspex5.rb +150 -103
- data/lib/aspera/cli/plugins/node.rb +68 -73
- data/lib/aspera/cli/plugins/orchestrator.rb +34 -44
- data/lib/aspera/cli/plugins/preview.rb +31 -31
- data/lib/aspera/cli/plugins/server.rb +31 -33
- data/lib/aspera/cli/plugins/shares.rb +13 -11
- data/lib/aspera/cli/sync_actions.rb +8 -8
- data/lib/aspera/cli/transfer_agent.rb +32 -19
- data/lib/aspera/cli/transfer_progress.rb +1 -1
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +5 -0
- data/lib/aspera/command_line_builder.rb +14 -14
- data/lib/aspera/coverage.rb +1 -2
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +2 -3
- data/lib/aspera/faspex_gw.rb +5 -6
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/id_generator.rb +2 -2
- data/lib/aspera/json_rpc.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +6 -6
- data/lib/aspera/keychain/macos_security.rb +27 -22
- data/lib/aspera/log.rb +2 -2
- data/lib/aspera/nagios.rb +3 -3
- data/lib/aspera/node_simulator.rb +5 -6
- data/lib/aspera/oauth/base.rb +143 -0
- data/lib/aspera/oauth/factory.rb +124 -0
- data/lib/aspera/oauth/generic.rb +34 -0
- data/lib/aspera/oauth/jwt.rb +51 -0
- data/lib/aspera/oauth/url_json.rb +31 -0
- data/lib/aspera/oauth/web.rb +50 -0
- data/lib/aspera/oauth.rb +5 -331
- data/lib/aspera/open_application.rb +7 -7
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +5 -5
- data/lib/aspera/preview/terminal.rb +3 -2
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +4 -4
- data/lib/aspera/rest.rb +175 -144
- data/lib/aspera/rest_errors_aspera.rb +3 -3
- data/lib/aspera/resumer.rb +77 -0
- data/lib/aspera/ssh.rb +6 -1
- data/lib/aspera/{fasp → transfer}/error.rb +3 -3
- data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
- data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
- data/lib/aspera/{fasp → transfer}/parameters.rb +58 -89
- data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +18 -16
- data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
- data/lib/aspera/{fasp → transfer}/sync.rb +32 -32
- data/lib/aspera/{fasp → transfer}/uri.rb +9 -8
- data/lib/aspera/web_server_simple.rb +11 -3
- data.tar.gz.sig +0 -0
- metadata +36 -63
- metadata.gz.sig +0 -0
- data/lib/aspera/aoc.rb +0 -601
- data/lib/aspera/ats_api.rb +0 -47
- data/lib/aspera/cos_node.rb +0 -94
- data/lib/aspera/fasp/resume_policy.rb +0 -79
- data/lib/aspera/node.rb +0 -339
@@ -15,10 +15,9 @@ require 'tty-spinner'
|
|
15
15
|
module Aspera
|
16
16
|
module Cli
|
17
17
|
module Plugins
|
18
|
-
class Faspex5 <
|
18
|
+
class Faspex5 < Cli::BasicAuthPlugin
|
19
19
|
RECIPIENT_TYPES = %w[user workgroup external_user distribution_list shared_inbox].freeze
|
20
20
|
PACKAGE_TERMINATED = %w[completed failed].freeze
|
21
|
-
API_DETECT = 'api/v5/configuration/ping'
|
22
21
|
# list of supported mailbox types (to list packages)
|
23
22
|
API_LIST_MAILBOX_TYPES = %w[inbox inbox_history inbox_all inbox_all_history outbox outbox_history pending pending_history all].freeze
|
24
23
|
PACKAGE_SEND_FROM_REMOTE_SOURCE = 'remote_source'
|
@@ -28,34 +27,49 @@ module Aspera
|
|
28
27
|
accounts contacts jobs workgroups shared_inboxes nodes oauth_clients registrations saml_configs
|
29
28
|
metadata_profiles email_notifications alternate_addresses
|
30
29
|
].freeze
|
30
|
+
# states for jobs not in final state
|
31
31
|
JOB_RUNNING = %w[queued working].freeze
|
32
|
-
|
32
|
+
PATH_STANDARD_ROOT = '/aspera/faspex'
|
33
|
+
PATH_API_V5 = 'api/v5'
|
34
|
+
# endpoint for authentication API
|
35
|
+
PATH_AUTH = 'auth'
|
36
|
+
PATH_HEALTH = 'configuration/ping'
|
33
37
|
PER_PAGE_DEFAULT = 100
|
34
|
-
|
38
|
+
# OAuth methods supported
|
39
|
+
STD_AUTH_TYPES = %i[web jwt boot].freeze
|
40
|
+
HEADER_ITERATION_TOKEN = 'X-Aspera-Next-Iteration-Token'
|
41
|
+
private_constant(*%i[JOB_RUNNING RECIPIENT_TYPES PACKAGE_TERMINATED PATH_HEALTH API_LIST_MAILBOX_TYPES PACKAGE_SEND_FROM_REMOTE_SOURCE PER_PAGE_DEFAULT
|
42
|
+
STD_AUTH_TYPES])
|
35
43
|
class << self
|
36
44
|
def application_name
|
37
45
|
'Faspex'
|
38
46
|
end
|
39
47
|
|
40
48
|
def detect(address_or_url)
|
49
|
+
# add scheme if missing
|
41
50
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
42
51
|
urls = [address_or_url]
|
43
|
-
urls.push("#{address_or_url}#{
|
44
|
-
|
52
|
+
urls.push("#{address_or_url}#{PATH_STANDARD_ROOT}") unless address_or_url.end_with?(PATH_STANDARD_ROOT)
|
53
|
+
error = nil
|
45
54
|
urls.each do |base_url|
|
55
|
+
# Faspex is always HTTPS
|
46
56
|
next unless base_url.start_with?('https://')
|
47
57
|
api = Rest.new(base_url: base_url, redirect_max: 1)
|
48
|
-
|
58
|
+
path_api_detect = "#{PATH_API_V5}/#{PATH_HEALTH}"
|
59
|
+
result = api.read(path_api_detect)
|
49
60
|
next unless result[:http].code.start_with?('2') && result[:http].body.strip.empty?
|
50
|
-
|
61
|
+
# end is at -1, and substract 1 for "/"
|
62
|
+
url_length = -2 - path_api_detect.length
|
51
63
|
# take redirect if any
|
52
64
|
return {
|
53
65
|
version: result[:http]['x-ibm-aspera'] || '5',
|
54
66
|
url: result[:http].uri.to_s[0..url_length]
|
55
67
|
}
|
56
68
|
rescue StandardError => e
|
69
|
+
error = e
|
57
70
|
Log.log.debug{"detect error: #{e}"}
|
58
71
|
end
|
72
|
+
raise error if error
|
59
73
|
return nil
|
60
74
|
end
|
61
75
|
|
@@ -91,31 +105,25 @@ module Aspera
|
|
91
105
|
}
|
92
106
|
end
|
93
107
|
|
108
|
+
# @return true if the URL is a public link
|
94
109
|
def public_link?(url)
|
95
|
-
url.include?('
|
110
|
+
url.include?('?context=')
|
96
111
|
end
|
97
112
|
end
|
98
113
|
|
99
|
-
def initialize(env)
|
100
|
-
super
|
114
|
+
def initialize(**env)
|
115
|
+
super
|
101
116
|
options.declare(:client_id, 'OAuth client identifier')
|
102
117
|
options.declare(:client_secret, 'OAuth client secret')
|
103
118
|
options.declare(:redirect_uri, 'OAuth redirect URI for web authentication')
|
104
|
-
options.declare(:auth, 'OAuth type of authentication', values:
|
119
|
+
options.declare(:auth, 'OAuth type of authentication', values: STD_AUTH_TYPES, default: :jwt)
|
105
120
|
options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
|
106
121
|
options.declare(:passphrase, 'OAuth JWT RSA private key passphrase')
|
107
122
|
options.declare(:box, "Package inbox, either shared inbox name or one of: #{API_LIST_MAILBOX_TYPES.join(', ')} or #{ExtendedValue::ALL}", default: 'inbox')
|
108
123
|
options.declare(:shared_folder, 'Send package with files from shared folder')
|
109
124
|
options.declare(:group_type, 'Type of shared box', values: %i[shared_inboxes workgroups], default: :shared_inboxes)
|
110
125
|
options.parse_options!
|
111
|
-
|
112
|
-
|
113
|
-
def api_url
|
114
|
-
return "#{@faspex5_api_base_url}/api/v5"
|
115
|
-
end
|
116
|
-
|
117
|
-
def auth_api_url
|
118
|
-
return "#{@faspex5_api_base_url}/auth"
|
126
|
+
@pub_link_context = nil
|
119
127
|
end
|
120
128
|
|
121
129
|
def set_api
|
@@ -124,60 +132,63 @@ module Aspera
|
|
124
132
|
auth_type = self.class.public_link?(@faspex5_api_base_url) ? :public_link : options.get_option(:auth, mandatory: true)
|
125
133
|
case auth_type
|
126
134
|
when :public_link
|
135
|
+
# resolve any redirect
|
136
|
+
@faspex5_api_base_url = Rest.new(base_url: @faspex5_api_base_url, redirect_max: 3).read('')[:http].uri.to_s
|
127
137
|
encoded_context = Rest.decode_query(URI.parse(@faspex5_api_base_url).query)['context']
|
128
138
|
raise 'Bad faspex5 public link, missing context in query' if encoded_context.nil?
|
139
|
+
# public link information (allowed usage)
|
129
140
|
@pub_link_context = JSON.parse(Base64.decode64(encoded_context))
|
130
141
|
Log.log.trace1{Log.dump(:@pub_link_context, @pub_link_context)}
|
131
142
|
# ok, we have the additional parameters, get the base url
|
132
143
|
@faspex5_api_base_url = @faspex5_api_base_url.gsub(%r{/public/.*}, '').gsub(/\?.*/, '')
|
133
|
-
@api_v5 = Rest.new(
|
134
|
-
base_url:
|
144
|
+
@api_v5 = Rest.new(
|
145
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_API_V5}",
|
135
146
|
headers: {'Passcode' => @pub_link_context['passcode']}
|
136
|
-
|
147
|
+
)
|
137
148
|
when :boot
|
138
149
|
# the password here is the token copied directly from browser in developer mode
|
139
|
-
@api_v5 = Rest.new(
|
140
|
-
base_url:
|
150
|
+
@api_v5 = Rest.new(
|
151
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_API_V5}",
|
141
152
|
headers: {'Authorization' => options.get_option(:password, mandatory: true)}
|
142
|
-
|
153
|
+
)
|
143
154
|
when :web
|
144
155
|
# opens a browser and ask user to auth using web
|
145
|
-
@api_v5 = Rest.new(
|
146
|
-
base_url:
|
156
|
+
@api_v5 = Rest.new(
|
157
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_API_V5}",
|
147
158
|
auth: {
|
148
159
|
type: :oauth2,
|
149
|
-
base_url:
|
160
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}",
|
150
161
|
grant_method: :web,
|
151
162
|
client_id: options.get_option(:client_id, mandatory: true),
|
152
|
-
|
153
|
-
}
|
163
|
+
redirect_uri: options.get_option(:redirect_uri, mandatory: true)
|
164
|
+
})
|
154
165
|
when :jwt
|
155
166
|
app_client_id = options.get_option(:client_id, mandatory: true)
|
156
|
-
@api_v5 = Rest.new(
|
157
|
-
base_url:
|
167
|
+
@api_v5 = Rest.new(
|
168
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_API_V5}",
|
158
169
|
auth: {
|
159
|
-
type:
|
160
|
-
|
161
|
-
|
162
|
-
client_id:
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
}})
|
173
|
-
else error_unexpected_value(auth_type)
|
170
|
+
type: :oauth2,
|
171
|
+
grant_method: :jwt,
|
172
|
+
base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}",
|
173
|
+
client_id: app_client_id,
|
174
|
+
payload: {
|
175
|
+
iss: app_client_id, # issuer
|
176
|
+
aud: app_client_id, # audience (this field is not clear...)
|
177
|
+
sub: "user:#{options.get_option(:username, mandatory: true)}" # subject is a user
|
178
|
+
},
|
179
|
+
private_key_obj: OpenSSL::PKey::RSA.new(options.get_option(:private_key, mandatory: true), options.get_option(:passphrase)),
|
180
|
+
headers: {typ: 'JWT'}
|
181
|
+
})
|
182
|
+
else Aspera.error_unexpected_value(auth_type)
|
174
183
|
end
|
184
|
+
# in case user wants to use HTTPGW tell transfer agent how to get address
|
185
|
+
transfer.httpgw_url_cb = lambda { @api_v5.read('account')[:data]['gateway_url'] }
|
175
186
|
end
|
176
187
|
|
177
188
|
# if recipient is just an email, then convert to expected API hash : name and type
|
178
189
|
def normalize_recipients(parameters)
|
179
190
|
return unless parameters.key?('recipients')
|
180
|
-
assert_type(parameters['recipients'], Array){'recipients'}
|
191
|
+
Aspera.assert_type(parameters['recipients'], Array){'recipients'}
|
181
192
|
recipient_types = RECIPIENT_TYPES
|
182
193
|
if parameters.key?('recipient_types')
|
183
194
|
recipient_types = parameters['recipient_types']
|
@@ -185,7 +196,7 @@ module Aspera
|
|
185
196
|
recipient_types = [recipient_types] unless recipient_types.is_a?(Array)
|
186
197
|
end
|
187
198
|
parameters['recipients'].map! do |recipient_data|
|
188
|
-
# if just a string,
|
199
|
+
# if just a string, make a general lookup and build expected name/type hash
|
189
200
|
if recipient_data.is_a?(String)
|
190
201
|
matched = @api_v5.lookup_by_name('contacts', recipient_data, {context: 'packages', type: Rest.array_params(recipient_types)})
|
191
202
|
recipient_data = {
|
@@ -238,7 +249,7 @@ module Aspera
|
|
238
249
|
spinner.spin
|
239
250
|
sleep(0.5)
|
240
251
|
end
|
241
|
-
error_unreachable_line
|
252
|
+
Aspera.error_unreachable_line
|
242
253
|
end
|
243
254
|
|
244
255
|
# Get a (full or partial) list of all entities of a given type
|
@@ -248,7 +259,7 @@ module Aspera
|
|
248
259
|
# @param item_list_key [String] key in the result to get the list of items
|
249
260
|
def list_entities(type:, real_path: nil, query: {}, item_list_key: nil)
|
250
261
|
type = type.to_s if type.is_a?(Symbol)
|
251
|
-
assert_type(type, String)
|
262
|
+
Aspera.assert_type(type, String)
|
252
263
|
item_list_key = type if item_list_key.nil?
|
253
264
|
full_path = real_path.nil? ? type : real_path
|
254
265
|
result = []
|
@@ -277,7 +288,7 @@ module Aspera
|
|
277
288
|
# lookup an entity id from its name
|
278
289
|
def lookup_entity_by_field(type:, value:, field: 'name', query: :default, real_path: nil, item_list_key: nil)
|
279
290
|
if query.eql?(:default)
|
280
|
-
assert(field.eql?('name')){'Default query is on name only'}
|
291
|
+
Aspera.assert(field.eql?('name')){'Default query is on name only'}
|
281
292
|
query = {'q'=> value}
|
282
293
|
end
|
283
294
|
found = list_entities(type: type, real_path: real_path, query: query, item_list_key: item_list_key).select{|i|i[field].eql?(value)}
|
@@ -313,7 +324,7 @@ module Aspera
|
|
313
324
|
if options.get_option(:once_only, mandatory: true)
|
314
325
|
# read ids from persistency
|
315
326
|
skip_ids_persistency = PersistencyActionOnce.new(
|
316
|
-
manager:
|
327
|
+
manager: persistency,
|
317
328
|
data: [],
|
318
329
|
id: IdGenerator.from_list([
|
319
330
|
'faspex_recv',
|
@@ -325,7 +336,7 @@ module Aspera
|
|
325
336
|
packages = []
|
326
337
|
case package_ids
|
327
338
|
when ExtendedValue::INIT
|
328
|
-
assert(skip_ids_persistency){'Only with option once_only'}
|
339
|
+
Aspera.assert(skip_ids_persistency){'Only with option once_only'}
|
329
340
|
skip_ids_persistency.data.clear.concat(list_packages_with_filter.map{|p|p['id']})
|
330
341
|
skip_ids_persistency.save
|
331
342
|
return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
|
@@ -339,8 +350,8 @@ module Aspera
|
|
339
350
|
else
|
340
351
|
# a single id was provided, or a list of ids
|
341
352
|
package_ids = [package_ids] unless package_ids.is_a?(Array)
|
342
|
-
assert_type(package_ids, Array){'Expecting a single package id or a list of ids'}
|
343
|
-
assert(package_ids.all?(String)){'Package id shall be String'}
|
353
|
+
Aspera.assert_type(package_ids, Array){'Expecting a single package id or a list of ids'}
|
354
|
+
Aspera.assert(package_ids.all?(String)){'Package id shall be String'}
|
344
355
|
# packages = package_ids.map{|pkg_id|@api_v5.read("packages/#{pkg_id}")[:data]}
|
345
356
|
packages = package_ids.map{|pkg_id|{'id'=>pkg_id}}
|
346
357
|
end
|
@@ -386,6 +397,45 @@ module Aspera
|
|
386
397
|
return Main.result_transfer_multiple(result_transfer)
|
387
398
|
end
|
388
399
|
|
400
|
+
# browse a folder
|
401
|
+
# @param browse_endpoint [String] the endpoint to browse
|
402
|
+
def browse_folder(browse_endpoint)
|
403
|
+
path = options.get_next_argument('folder path', mandatory: false, default: '/')
|
404
|
+
query = query_read_delete(default: {})
|
405
|
+
query['filters'] = {} unless query.key?('filters')
|
406
|
+
filters = query.delete('filters')
|
407
|
+
filters['basenames'] = [] unless filters.key?('basenames')
|
408
|
+
Aspera.assert_type(filters, Hash){'filters'}
|
409
|
+
max_items = query.delete('max')
|
410
|
+
recursive = query.delete('recursive')
|
411
|
+
all_items = []
|
412
|
+
folders_to_process = [path]
|
413
|
+
until folders_to_process.empty?
|
414
|
+
path = folders_to_process.shift
|
415
|
+
query.delete('iteration_token')
|
416
|
+
loop do
|
417
|
+
response = @api_v5.call(
|
418
|
+
operation: 'POST',
|
419
|
+
subpath: browse_endpoint,
|
420
|
+
headers: {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
|
421
|
+
url_params: query,
|
422
|
+
json_params: {'path' => path, 'filters' => filters})
|
423
|
+
all_items.concat(response[:data]['items'])
|
424
|
+
if recursive
|
425
|
+
folders_to_process.concat(response[:data]['items'].select{|i|i['type'].eql?('directory')}.map{|i|i['path']})
|
426
|
+
end
|
427
|
+
if !max_items.nil? && (all_items.count >= max_items)
|
428
|
+
all_items = all_items.slice(0, max_items) if all_items.count > max_items
|
429
|
+
break
|
430
|
+
end
|
431
|
+
iteration_token = response[:http][HEADER_ITERATION_TOKEN]
|
432
|
+
break if iteration_token.nil? || iteration_token.empty?
|
433
|
+
query['iteration_token'] = iteration_token
|
434
|
+
end
|
435
|
+
end
|
436
|
+
return {type: :object_list, data: all_items}
|
437
|
+
end
|
438
|
+
|
389
439
|
def package_action
|
390
440
|
command = options.get_next_command(%i[show browse status delete receive send list])
|
391
441
|
package_id =
|
@@ -396,36 +446,34 @@ module Aspera
|
|
396
446
|
when :show
|
397
447
|
return {type: :single_object, data: @api_v5.read("packages/#{package_id}")[:data]}
|
398
448
|
when :browse
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
}
|
406
|
-
result = @api_v5.call({
|
407
|
-
operation: 'POST',
|
408
|
-
subpath: "packages/#{package_id}/files/received",
|
409
|
-
headers: {'Accept' => 'application/json'},
|
410
|
-
url_params: params,
|
411
|
-
json_params: {'path' => path, 'filters' => {'basenames'=>[]}}})[:data]
|
412
|
-
formatter.display_item_count(result['item_count'], result['total_count'])
|
413
|
-
return {type: :object_list, data: result['items']}
|
449
|
+
location = case options.get_option(:box)
|
450
|
+
when 'inbox' then 'received'
|
451
|
+
when 'outbox' then 'sent'
|
452
|
+
else raise 'Browse only available for inbox and outbox'
|
453
|
+
end
|
454
|
+
return browse_folder("packages/#{package_id}/files/#{location}")
|
414
455
|
when :status
|
415
456
|
status = wait_package_status(package_id, status_list: nil)
|
416
457
|
return {type: :single_object, data: status}
|
417
458
|
when :delete
|
418
459
|
ids = package_id
|
419
460
|
ids = [ids] unless ids.is_a?(Array)
|
420
|
-
assert_type(ids, Array){'Package identifier'}
|
421
|
-
assert(ids.all?(String)){'Package id shall be String'}
|
461
|
+
Aspera.assert_type(ids, Array){'Package identifier'}
|
462
|
+
Aspera.assert(ids.all?(String)){'Package id shall be String'}
|
422
463
|
# API returns 204, empty on success
|
423
|
-
@api_v5.call(
|
464
|
+
@api_v5.call(operation: 'DELETE', subpath: 'packages', headers: {'Accept' => 'application/json'}, json_params: {ids: ids})
|
424
465
|
return Main.result_status('Package(s) deleted')
|
425
466
|
when :receive
|
426
467
|
return package_receive(package_id)
|
427
468
|
when :send
|
428
469
|
parameters = value_create_modify(command: command)
|
470
|
+
# autofill recipient for public url
|
471
|
+
if @pub_link_context&.key?('recipient_type') && !parameters.key?('recipients')
|
472
|
+
parameters['recipients'] = [{
|
473
|
+
name: @pub_link_context['name'],
|
474
|
+
recipient_type: @pub_link_context['recipient_type']
|
475
|
+
}]
|
476
|
+
end
|
429
477
|
normalize_recipients(parameters)
|
430
478
|
package = @api_v5.create('packages', parameters)[:data]
|
431
479
|
shared_folder = options.get_option(:shared_folder)
|
@@ -465,7 +513,7 @@ module Aspera
|
|
465
513
|
end # case package
|
466
514
|
end
|
467
515
|
|
468
|
-
ACTIONS = %i[health version user bearer_token packages shared_folders admin gateway postprocessing].freeze
|
516
|
+
ACTIONS = %i[health version user bearer_token packages shared_folders admin gateway postprocessing invitations].freeze
|
469
517
|
|
470
518
|
def execute_action
|
471
519
|
command = options.get_next_command(ACTIONS)
|
@@ -485,7 +533,9 @@ module Aspera
|
|
485
533
|
end
|
486
534
|
return nagios.result
|
487
535
|
when :user
|
488
|
-
case options.get_next_command(%i[profile])
|
536
|
+
case options.get_next_command(%i[account profile])
|
537
|
+
when :account
|
538
|
+
return { type: :single_object, data: @api_v5.read('account')[:data] }
|
489
539
|
when :profile
|
490
540
|
case options.get_next_command(%i[show modify])
|
491
541
|
when :show
|
@@ -511,21 +561,9 @@ module Aspera
|
|
511
561
|
raise "multiple matches for #{field} = #{value}" if matches.length > 1
|
512
562
|
matches.first['id']
|
513
563
|
end
|
514
|
-
path = options.get_next_argument('folder path', mandatory: false) || '/'
|
515
564
|
node = all_shared_folders.find{|i|i['id'].eql?(shared_folder_id)}
|
516
565
|
raise "No such shared folder id #{shared_folder_id}" if node.nil?
|
517
|
-
|
518
|
-
operation: 'POST',
|
519
|
-
subpath: "nodes/#{node['node_id']}/shared_folders/#{shared_folder_id}/browse",
|
520
|
-
headers: {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
|
521
|
-
json_params: {'path': path, 'filters': {'basenames': []}},
|
522
|
-
url_params: {offset: 0, limit: 100}
|
523
|
-
})[:data]
|
524
|
-
if result.key?('items')
|
525
|
-
return {type: :object_list, data: result['items']}
|
526
|
-
else
|
527
|
-
return {type: :single_object, data: result['self']}
|
528
|
-
end
|
566
|
+
return browse_folder("nodes/#{node['node_id']}/shared_folders/#{shared_folder_id}/browse")
|
529
567
|
end
|
530
568
|
when :admin
|
531
569
|
case options.get_next_command(%i[resource smtp].freeze)
|
@@ -550,12 +588,12 @@ module Aspera
|
|
550
588
|
display_fields = Formatter.all_but('user_profile_data_attributes')
|
551
589
|
when :oauth_clients
|
552
590
|
display_fields = Formatter.all_but('public_key')
|
553
|
-
adm_api = Rest.new(
|
591
|
+
adm_api = Rest.new(**@api_v5.params.merge(base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}"))
|
554
592
|
when :shared_inboxes, :workgroups
|
555
593
|
available_commands.push(:members, :saml_groups, :invite_external_collaborator)
|
556
594
|
special_query = {'all': true}
|
557
595
|
when :nodes
|
558
|
-
available_commands.push(:shared_folders)
|
596
|
+
available_commands.push(:shared_folders, :browse)
|
559
597
|
end
|
560
598
|
res_command = options.get_next_command(available_commands)
|
561
599
|
case res_command
|
@@ -573,6 +611,8 @@ module Aspera
|
|
573
611
|
lookup_entity_by_field(
|
574
612
|
type: 'shared_folders', real_path: sh_path, field: field, value: value)['id']
|
575
613
|
end
|
614
|
+
when :browse
|
615
|
+
return browse_folder("#{res_path}/#{instance_identifier}/browse")
|
576
616
|
when :invite_external_collaborator
|
577
617
|
shared_inbox_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value)['id']}
|
578
618
|
creation_payload = value_create_modify(command: res_command, type: [Hash, String])
|
@@ -637,34 +677,41 @@ module Aspera
|
|
637
677
|
return { type: :single_object, data: result }
|
638
678
|
end
|
639
679
|
end
|
680
|
+
when :invitations
|
681
|
+
invitation_endpoint = 'invitations'
|
682
|
+
invitation_command = options.get_next_command(%i[resend].concat(Plugin::ALL_OPS))
|
683
|
+
case invitation_command
|
684
|
+
when :create
|
685
|
+
return do_bulk_operation(command: invitation_command, descr: 'data') do |params|
|
686
|
+
invitation_endpoint = params.key?('recipient_name') ? 'public_invitations' : 'invitations'
|
687
|
+
@api_v5.create(invitation_endpoint, params)[:data]
|
688
|
+
end
|
689
|
+
when :resend
|
690
|
+
@api_v5.create("#{invitation_endpoint}/#{instance_identifier}/resend")
|
691
|
+
return Main.result_status('Invitation resent')
|
692
|
+
else
|
693
|
+
return entity_command(
|
694
|
+
invitation_command, @api_v5, invitation_endpoint, item_list_key: invitation_endpoint,
|
695
|
+
display_fields: %w[id public recipient_type recipient_name email_address])
|
696
|
+
end
|
640
697
|
when :gateway
|
641
698
|
require 'aspera/faspex_gw'
|
642
699
|
url = value_create_modify(command: command, description: 'listening url (e.g. https://localhost:12345)', type: String)
|
643
700
|
uri = URI.parse(url)
|
644
701
|
server = WebServerSimple.new(uri)
|
645
702
|
server.mount(uri.path, Faspex4GWServlet, @api_v5, nil)
|
646
|
-
# on ctrl-c, tell server main loop to exit
|
647
|
-
trap('INT') { server.shutdown }
|
648
|
-
formatter.display_status("Gateway for Faspex 4-style API listening on #{url}")
|
649
|
-
Log.log.info("Listening on #{url}")
|
650
|
-
# this is blocking until server exits
|
651
703
|
server.start
|
652
704
|
return Main.result_status('Gateway terminated')
|
653
705
|
when :postprocessing
|
654
706
|
require 'aspera/faspex_postproc' # cspell:disable-line
|
655
707
|
parameters = value_create_modify(command: command)
|
656
708
|
parameters = parameters.symbolize_keys
|
657
|
-
assert(parameters.key?(:url)){'Missing key: url'}
|
709
|
+
Aspera.assert(parameters.key?(:url)){'Missing key: url'}
|
658
710
|
uri = URI.parse(parameters[:url])
|
659
711
|
parameters[:processing] ||= {}
|
660
712
|
parameters[:processing][:root] = uri.path
|
661
713
|
server = WebServerSimple.new(uri, certificate: parameters[:certificate])
|
662
714
|
server.mount(uri.path, Faspex4PostProcServlet, parameters[:processing])
|
663
|
-
# on ctrl-c, tell server main loop to exit
|
664
|
-
trap('INT') { server.shutdown }
|
665
|
-
formatter.display_status("Web-hook for Faspex 4-style post processing listening on #{uri.port}")
|
666
|
-
Log.log.info("Listening on #{uri.port}")
|
667
|
-
# this is blocking until server exits
|
668
715
|
server.start
|
669
716
|
return Main.result_status('Gateway terminated')
|
670
717
|
end # case command
|