aspera-cli 4.17.0 → 4.18.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -4
- data/CHANGELOG.md +23 -0
- data/CONTRIBUTING.md +15 -1
- data/README.md +620 -378
- data/bin/ascli +5 -0
- data/bin/asession +2 -2
- data/lib/aspera/agent/alpha.rb +6 -4
- data/lib/aspera/agent/base.rb +9 -6
- data/lib/aspera/agent/connect.rb +4 -4
- data/lib/aspera/agent/direct.rb +56 -37
- data/lib/aspera/agent/httpgw.rb +23 -324
- data/lib/aspera/agent/node.rb +19 -20
- data/lib/aspera/agent/trsdk.rb +19 -20
- data/lib/aspera/api/aoc.rb +17 -14
- data/lib/aspera/api/cos_node.rb +4 -4
- data/lib/aspera/api/httpgw.rb +339 -0
- data/lib/aspera/api/node.rb +34 -21
- data/lib/aspera/ascmd.rb +4 -3
- data/lib/aspera/ascp/installation.rb +15 -7
- data/lib/aspera/ascp/management.rb +2 -2
- data/lib/aspera/cli/basic_auth_plugin.rb +5 -9
- data/lib/aspera/cli/extended_value.rb +12 -6
- data/lib/aspera/cli/formatter.rb +155 -65
- data/lib/aspera/cli/hints.rb +18 -0
- data/lib/aspera/cli/main.rb +22 -29
- data/lib/aspera/cli/manager.rb +53 -36
- data/lib/aspera/cli/plugin.rb +26 -17
- data/lib/aspera/cli/plugin_factory.rb +31 -20
- data/lib/aspera/cli/plugins/alee.rb +14 -2
- data/lib/aspera/cli/plugins/aoc.rb +141 -131
- data/lib/aspera/cli/plugins/ats.rb +1 -1
- data/lib/aspera/cli/plugins/config.rb +52 -46
- data/lib/aspera/cli/plugins/console.rb +8 -5
- data/lib/aspera/cli/plugins/faspex.rb +27 -19
- data/lib/aspera/cli/plugins/faspex5.rb +222 -149
- data/lib/aspera/cli/plugins/faspio.rb +85 -0
- data/lib/aspera/cli/plugins/httpgw.rb +55 -0
- data/lib/aspera/cli/plugins/node.rb +86 -29
- data/lib/aspera/cli/plugins/orchestrator.rb +31 -29
- data/lib/aspera/cli/plugins/preview.rb +6 -2
- data/lib/aspera/cli/plugins/server.rb +5 -5
- data/lib/aspera/cli/plugins/shares.rb +16 -14
- data/lib/aspera/cli/sync_actions.rb +6 -6
- data/lib/aspera/cli/transfer_agent.rb +5 -4
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +7 -6
- data/lib/aspera/faspex_gw.rb +5 -4
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/log.rb +6 -3
- data/lib/aspera/node_simulator.rb +2 -2
- data/lib/aspera/oauth/base.rb +31 -19
- data/lib/aspera/oauth/factory.rb +12 -13
- data/lib/aspera/oauth/generic.rb +1 -0
- data/lib/aspera/oauth/jwt.rb +18 -15
- data/lib/aspera/oauth/url_json.rb +8 -6
- data/lib/aspera/open_application.rb +5 -7
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +3 -3
- data/lib/aspera/preview/options.rb +3 -3
- data/lib/aspera/preview/terminal.rb +4 -4
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +5 -1
- data/lib/aspera/rest.rb +60 -74
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +2 -2
- data/lib/aspera/rest_errors_aspera.rb +1 -1
- data/lib/aspera/resumer.rb +1 -1
- data/lib/aspera/secret_hider.rb +2 -4
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/transfer/parameters.rb +39 -36
- data/lib/aspera/transfer/spec.rb +2 -0
- data/lib/aspera/transfer/sync.rb +2 -1
- data/lib/aspera/transfer/uri.rb +1 -1
- data/lib/aspera/uri_reader.rb +5 -4
- data/lib/aspera/web_auth.rb +1 -1
- data/lib/aspera/web_server_simple.rb +4 -3
- data.tar.gz.sig +0 -0
- metadata +5 -3
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/plugins/bss.rb +0 -71
@@ -18,7 +18,10 @@ module Aspera
|
|
18
18
|
next unless base_url.start_with?('https://')
|
19
19
|
api = Rest.new(base_url: base_url, redirect_max: 2)
|
20
20
|
test_endpoint = 'login'
|
21
|
-
test_page = api.call(
|
21
|
+
test_page = api.call(
|
22
|
+
operation: 'GET',
|
23
|
+
subpath: test_endpoint,
|
24
|
+
query: {local: true})
|
22
25
|
next unless test_page[:http].body.include?('Aspera Console')
|
23
26
|
version = 'unknown'
|
24
27
|
if (m = test_page[:http].body.match(/\(v([1-9]\..*)\)/))
|
@@ -102,7 +105,7 @@ module Aspera
|
|
102
105
|
end
|
103
106
|
end
|
104
107
|
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -179,7 +179,11 @@ module Aspera
|
|
179
179
|
loop do
|
180
180
|
# get a batch of package information
|
181
181
|
# order: first batch is latest packages, and then in a batch ids are increasing
|
182
|
-
atom_xml = api_v3.call(
|
182
|
+
atom_xml = api_v3.call(
|
183
|
+
operation: 'GET',
|
184
|
+
subpath: "#{mailbox}.atom",
|
185
|
+
headers: {'Accept' => 'application/xml'},
|
186
|
+
query: mailbox_query)[:http].body
|
183
187
|
box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => %w[entry field link to]})
|
184
188
|
Log.log.debug{Log.dump(:box_data, box_data)}
|
185
189
|
items = box_data.key?('entry') ? box_data['entry'] : []
|
@@ -246,8 +250,9 @@ module Aspera
|
|
246
250
|
package_creation_data = api_public_link.call(
|
247
251
|
operation: 'POST',
|
248
252
|
subpath: create_path,
|
249
|
-
|
250
|
-
|
253
|
+
headers: {'Accept' => 'text/javascript'},
|
254
|
+
body: package_create_params,
|
255
|
+
body_type: :json)[:http].body
|
251
256
|
# get arguments of function call
|
252
257
|
package_creation_data.delete!("\n") # one line
|
253
258
|
package_creation_data.gsub!(/^[^"]+\("\{/, '{') # delete header
|
@@ -308,8 +313,9 @@ module Aspera
|
|
308
313
|
pkg_created = api_v3.call(
|
309
314
|
operation: 'POST',
|
310
315
|
subpath: 'send',
|
311
|
-
|
312
|
-
|
316
|
+
headers: {'Accept' => 'application/json'},
|
317
|
+
body: package_create_params,
|
318
|
+
body_type: :json
|
313
319
|
)[:data]
|
314
320
|
if first_source.key?('id')
|
315
321
|
# no transfer spec if remote source: handled by faspex
|
@@ -380,9 +386,9 @@ module Aspera
|
|
380
386
|
api_public_link = Rest.new(base_url: link_data[:base_url])
|
381
387
|
package_creation_data = api_public_link.call(
|
382
388
|
operation: 'GET',
|
383
|
-
subpath:
|
384
|
-
|
385
|
-
|
389
|
+
subpath: link_data[:subpath],
|
390
|
+
headers: {'Accept' => 'application/xml'},
|
391
|
+
query: {passcode: link_data[:query]['passcode']})
|
386
392
|
if !package_creation_data[:http].body.start_with?('<?xml ')
|
387
393
|
OpenApplication.instance.uri(link_url)
|
388
394
|
raise Cli::Error, 'Unexpected response: package not found ?'
|
@@ -391,7 +397,7 @@ module Aspera
|
|
391
397
|
Log.log.debug{Log.dump(:package_entry, package_entry)}
|
392
398
|
transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
|
393
399
|
pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
|
394
|
-
end
|
400
|
+
end
|
395
401
|
# prune packages already downloaded
|
396
402
|
# TODO : remove ids from skip not present in inbox to avoid growing too big
|
397
403
|
# skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
|
@@ -411,10 +417,12 @@ module Aspera
|
|
411
417
|
xml_payload =
|
412
418
|
%Q(<?xml version="1.0" encoding="UTF-8"?><url-list xmlns="http://schemas.asperasoft.com/xml/url-list"><url href="#{sanitized}"/></url-list>)
|
413
419
|
transfer_spec['token'] = api_v3.call(
|
414
|
-
operation:
|
415
|
-
subpath:
|
416
|
-
headers:
|
417
|
-
|
420
|
+
operation: 'POST',
|
421
|
+
subpath: 'issue-token',
|
422
|
+
headers: {'Accept' => 'text/plain', 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
|
423
|
+
query: {'direction' => 'down'},
|
424
|
+
body: xml_payload,
|
425
|
+
body_type: :text)[:http].body
|
418
426
|
end
|
419
427
|
transfer_spec['direction'] = Transfer::Spec::DIRECTION_RECEIVE
|
420
428
|
statuses = transfer.start(transfer_spec)
|
@@ -502,9 +510,9 @@ module Aspera
|
|
502
510
|
when :address_book
|
503
511
|
result = api_v3.call(
|
504
512
|
operation: 'GET',
|
505
|
-
subpath:
|
506
|
-
headers:
|
507
|
-
|
513
|
+
subpath: 'address-book',
|
514
|
+
headers: {'Accept' => 'application/json'},
|
515
|
+
query: {'format' => 'json', 'count' => 100_000}
|
508
516
|
)[:data]
|
509
517
|
formatter.display_status("users: #{result['itemsPerPage']}/#{result['totalResults']}, start:#{result['startIndex']}")
|
510
518
|
users = result['entry']
|
@@ -526,9 +534,9 @@ module Aspera
|
|
526
534
|
login_meths = api_v3.call(operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'})[:http].body
|
527
535
|
login_methods = XmlSimple.xml_in(login_meths, {'ForceArray' => false})
|
528
536
|
return {type: :object_list, data: login_methods['XRD']['Service']}
|
529
|
-
end
|
537
|
+
end
|
530
538
|
end
|
531
539
|
end
|
532
540
|
end
|
533
|
-
end
|
534
|
-
end
|
541
|
+
end
|
542
|
+
end
|
@@ -10,7 +10,6 @@ require 'aspera/nagios'
|
|
10
10
|
require 'aspera/environment'
|
11
11
|
require 'aspera/assert'
|
12
12
|
require 'securerandom'
|
13
|
-
require 'tty-spinner'
|
14
13
|
|
15
14
|
module Aspera
|
16
15
|
module Cli
|
@@ -24,8 +23,8 @@ module Aspera
|
|
24
23
|
# Faspex API v5: get transfer spec for connect
|
25
24
|
TRANSFER_CONNECT = 'connect'
|
26
25
|
ADMIN_RESOURCES = %i[
|
27
|
-
accounts contacts jobs workgroups shared_inboxes nodes oauth_clients registrations saml_configs
|
28
|
-
metadata_profiles email_notifications alternate_addresses
|
26
|
+
accounts distribution_lists contacts jobs workgroups shared_inboxes nodes oauth_clients registrations saml_configs
|
27
|
+
metadata_profiles email_notifications alternate_addresses webhooks
|
29
28
|
].freeze
|
30
29
|
# states for jobs not in final state
|
31
30
|
JOB_RUNNING = %w[queued working].freeze
|
@@ -58,7 +57,7 @@ module Aspera
|
|
58
57
|
path_api_detect = "#{PATH_API_V5}/#{PATH_HEALTH}"
|
59
58
|
result = api.read(path_api_detect)
|
60
59
|
next unless result[:http].code.start_with?('2') && result[:http].body.strip.empty?
|
61
|
-
# end is at -1, and
|
60
|
+
# end is at -1, and subtract 1 for "/"
|
62
61
|
url_length = -2 - path_api_detect.length
|
63
62
|
# take redirect if any
|
64
63
|
return {
|
@@ -237,31 +236,27 @@ module Aspera
|
|
237
236
|
end
|
238
237
|
|
239
238
|
def wait_for_job(job_id)
|
240
|
-
spinner = nil
|
241
239
|
loop do
|
242
240
|
status = @api_v5.read("jobs/#{job_id}", {type: :formatted})[:data]
|
243
241
|
return status unless JOB_RUNNING.include?(status['status'])
|
244
|
-
|
245
|
-
spinner = TTY::Spinner.new('[:spinner] :title', format: :classic)
|
246
|
-
spinner.start
|
247
|
-
end
|
248
|
-
spinner.update(title: status['status'])
|
249
|
-
spinner.spin
|
242
|
+
formatter.long_operation_running(status['status'])
|
250
243
|
sleep(0.5)
|
251
244
|
end
|
252
245
|
Aspera.error_unreachable_line
|
253
246
|
end
|
254
247
|
|
255
|
-
# Get a (full or partial) list of all entities of a given type
|
248
|
+
# Get a (full or partial) list of all entities of a given type with query: offset/limit
|
256
249
|
# @param type [String] the type of entity to list (just a name)
|
257
250
|
# @param query [Hash,nil] additional query parameters
|
258
251
|
# @param real_path [String] real path if it's n ot just the type
|
259
252
|
# @param item_list_key [String] key in the result to get the list of items
|
260
|
-
def list_entities(type:, real_path: nil,
|
253
|
+
def list_entities(type:, real_path: nil, item_list_key: nil, query: {})
|
254
|
+
Log.log.trace1{"list_entities t=#{type} p=#{real_path} k=#{item_list_key} q=#{query}"}
|
261
255
|
type = type.to_s if type.is_a?(Symbol)
|
262
256
|
Aspera.assert_type(type, String)
|
257
|
+
Aspera.assert_type(query, Hash)
|
263
258
|
item_list_key = type if item_list_key.nil?
|
264
|
-
|
259
|
+
real_path = type if real_path.nil?
|
265
260
|
result = []
|
266
261
|
offset = 0
|
267
262
|
max_items = query.delete(MAX_ITEMS)
|
@@ -270,7 +265,8 @@ module Aspera
|
|
270
265
|
query = {'limit'=> PER_PAGE_DEFAULT}.merge(query)
|
271
266
|
loop do
|
272
267
|
query['offset'] = offset
|
273
|
-
page_result = @api_v5.read(
|
268
|
+
page_result = @api_v5.read(real_path, query)[:data]
|
269
|
+
Aspera.assert_type(page_result[item_list_key], Array)
|
274
270
|
result.concat(page_result[item_list_key])
|
275
271
|
# reach the limit set by user ?
|
276
272
|
if !max_items.nil? && (result.length >= max_items)
|
@@ -281,12 +277,19 @@ module Aspera
|
|
281
277
|
remain_pages -= 1 unless remain_pages.nil?
|
282
278
|
break if remain_pages == 0
|
283
279
|
offset += page_result[item_list_key].length
|
280
|
+
formatter.long_operation_running
|
284
281
|
end
|
285
282
|
return result
|
286
283
|
end
|
287
284
|
|
288
285
|
# lookup an entity id from its name
|
289
|
-
|
286
|
+
# @param type [String] the type of entity to lookup, by default it is the path, and it is also the field name in result
|
287
|
+
# @param value [String] the value to lookup
|
288
|
+
# @param field [String] the field to match, by default it is 'name'
|
289
|
+
# @param real_path [String] real path if it's not just the type (override type)
|
290
|
+
# @param item_list_key [String] key in the result to get the list of items (override type)
|
291
|
+
# @param query [Hash] additional query parameters
|
292
|
+
def lookup_entity_by_field(type:, value:, field: 'name', real_path: nil, item_list_key: nil, query: :default)
|
290
293
|
if query.eql?(:default)
|
291
294
|
Aspera.assert(field.eql?('name')){'Default query is on name only'}
|
292
295
|
query = {'q'=> value}
|
@@ -381,8 +384,9 @@ module Aspera
|
|
381
384
|
operation: 'POST',
|
382
385
|
subpath: "packages/#{pkg_id}/transfer_spec/download",
|
383
386
|
headers: {'Accept' => 'application/json'},
|
384
|
-
|
385
|
-
|
387
|
+
query: download_params,
|
388
|
+
body: param_file_list,
|
389
|
+
body_type: :json
|
386
390
|
)[:data]
|
387
391
|
# delete flag for Connect Client
|
388
392
|
transfer_spec.delete('authentication')
|
@@ -400,7 +404,7 @@ module Aspera
|
|
400
404
|
# browse a folder
|
401
405
|
# @param browse_endpoint [String] the endpoint to browse
|
402
406
|
def browse_folder(browse_endpoint)
|
403
|
-
|
407
|
+
folders_to_process = [options.get_next_argument('folder path', mandatory: false, default: '/')]
|
404
408
|
query = query_read_delete(default: {})
|
405
409
|
query['filters'] = {} unless query.key?('filters')
|
406
410
|
filters = query.delete('filters')
|
@@ -409,17 +413,16 @@ module Aspera
|
|
409
413
|
max_items = query.delete('max')
|
410
414
|
recursive = query.delete('recursive')
|
411
415
|
all_items = []
|
412
|
-
folders_to_process = [path]
|
413
416
|
until folders_to_process.empty?
|
414
417
|
path = folders_to_process.shift
|
415
|
-
query.delete('iteration_token')
|
416
418
|
loop do
|
417
419
|
response = @api_v5.call(
|
418
420
|
operation: 'POST',
|
419
421
|
subpath: browse_endpoint,
|
420
|
-
headers: {'Accept' => 'application/json'
|
421
|
-
|
422
|
-
|
422
|
+
headers: {'Accept' => 'application/json'},
|
423
|
+
query: query,
|
424
|
+
body: {'path' => path, 'filters' => filters},
|
425
|
+
body_type: :json)
|
423
426
|
all_items.concat(response[:data]['items'])
|
424
427
|
if recursive
|
425
428
|
folders_to_process.concat(response[:data]['items'].select{|i|i['type'].eql?('directory')}.map{|i|i['path']})
|
@@ -431,7 +434,9 @@ module Aspera
|
|
431
434
|
iteration_token = response[:http][HEADER_ITERATION_TOKEN]
|
432
435
|
break if iteration_token.nil? || iteration_token.empty?
|
433
436
|
query['iteration_token'] = iteration_token
|
437
|
+
formatter.long_operation_running(all_items.count)
|
434
438
|
end
|
439
|
+
query.delete('iteration_token')
|
435
440
|
end
|
436
441
|
return {type: :object_list, data: all_items}
|
437
442
|
end
|
@@ -459,9 +464,14 @@ module Aspera
|
|
459
464
|
ids = package_id
|
460
465
|
ids = [ids] unless ids.is_a?(Array)
|
461
466
|
Aspera.assert_type(ids, Array){'Package identifier'}
|
462
|
-
Aspera.assert(ids.all?(String)){
|
467
|
+
Aspera.assert(ids.all?(String)){"Package id(s) shall be String, but have: #{ids.map(&:class).uniq.join(', ')}"}
|
463
468
|
# API returns 204, empty on success
|
464
|
-
@api_v5.call(
|
469
|
+
@api_v5.call(
|
470
|
+
operation: 'DELETE',
|
471
|
+
subpath: 'packages',
|
472
|
+
headers: {'Accept' => 'application/json'},
|
473
|
+
body: {ids: ids},
|
474
|
+
body_type: :json)
|
465
475
|
return Main.result_status('Package(s) deleted')
|
466
476
|
when :receive
|
467
477
|
return package_receive(package_id)
|
@@ -483,8 +493,9 @@ module Aspera
|
|
483
493
|
operation: 'POST',
|
484
494
|
subpath: "packages/#{package['id']}/transfer_spec/upload",
|
485
495
|
headers: {'Accept' => 'application/json'},
|
486
|
-
|
487
|
-
|
496
|
+
query: {transfer_type: TRANSFER_CONNECT},
|
497
|
+
body: {paths: transfer.source_list},
|
498
|
+
body_type: :json
|
488
499
|
)[:data]
|
489
500
|
# well, we asked a TS for connect, but we actually want a generic one
|
490
501
|
transfer_spec.delete('authentication')
|
@@ -492,7 +503,10 @@ module Aspera
|
|
492
503
|
else
|
493
504
|
# send from remote shared folder
|
494
505
|
if (m = shared_folder.match(REGEX_LOOKUP_ID_BY_FIELD))
|
495
|
-
shared_folder = lookup_entity_by_field(
|
506
|
+
shared_folder = lookup_entity_by_field(
|
507
|
+
type: 'shared_folders',
|
508
|
+
field: m[1],
|
509
|
+
value: ExtendedValue.instance.evaluate(m[2]))['id']
|
496
510
|
end
|
497
511
|
transfer_request = {shared_folder_id: shared_folder, paths: transfer.source_list}
|
498
512
|
# start remote transfer and get first status
|
@@ -510,7 +524,174 @@ module Aspera
|
|
510
524
|
data: list_packages_with_filter,
|
511
525
|
fields: %w[id title release_date total_bytes total_files created_time state]
|
512
526
|
}
|
513
|
-
end
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
def execute_resource(res_type)
|
531
|
+
list_key = res_path = res_type.to_s
|
532
|
+
id_as_arg = false
|
533
|
+
display_fields = nil
|
534
|
+
adm_api = @api_v5
|
535
|
+
res_id_query = :default
|
536
|
+
delete_style = nil
|
537
|
+
available_commands = [].concat(Plugin::ALL_OPS)
|
538
|
+
case res_type
|
539
|
+
when :metadata_profiles
|
540
|
+
res_path = 'configuration/metadata_profiles'
|
541
|
+
list_key = 'profiles'
|
542
|
+
when :alternate_addresses
|
543
|
+
res_path = 'configuration/alternate_addresses'
|
544
|
+
when :distribution_lists
|
545
|
+
res_path = 'account/distribution_lists'
|
546
|
+
list_key = 'distribution_lists'
|
547
|
+
delete_style = 'ids'
|
548
|
+
when :email_notifications
|
549
|
+
list_key = false
|
550
|
+
id_as_arg = 'type'
|
551
|
+
when :accounts
|
552
|
+
display_fields = Formatter.all_but('user_profile_data_attributes')
|
553
|
+
when :oauth_clients
|
554
|
+
display_fields = Formatter.all_but('public_key')
|
555
|
+
adm_api = Rest.new(**@api_v5.params.merge(base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}"))
|
556
|
+
when :shared_inboxes, :workgroups
|
557
|
+
available_commands.push(:members, :saml_groups, :invite_external_collaborator)
|
558
|
+
res_id_query = {'all': true}
|
559
|
+
when :nodes
|
560
|
+
available_commands.push(:shared_folders, :browse)
|
561
|
+
end
|
562
|
+
res_command = options.get_next_command(available_commands)
|
563
|
+
case res_command
|
564
|
+
when *Plugin::ALL_OPS
|
565
|
+
return entity_command(res_command, adm_api, res_path, item_list_key: list_key, display_fields: display_fields, id_as_arg: id_as_arg, delete_style: delete_style) do |field, value|
|
566
|
+
lookup_entity_by_field(
|
567
|
+
type: res_type, value: value, field: field, real_path: res_path, item_list_key: list_key, query: res_id_query)['id']
|
568
|
+
end
|
569
|
+
when :shared_folders
|
570
|
+
node_id = instance_identifier do |field, value|
|
571
|
+
lookup_entity_by_field(type: res_type, field: field, value: value)['id']
|
572
|
+
end
|
573
|
+
sh_path = "#{res_path}/#{node_id}/shared_folders"
|
574
|
+
sh_command = options.get_next_command([:user].concat(Plugin::ALL_OPS))
|
575
|
+
case sh_command
|
576
|
+
when *Plugin::ALL_OPS
|
577
|
+
return entity_command(sh_command, adm_api, sh_path, item_list_key: 'shared_folders') do |field, value|
|
578
|
+
lookup_entity_by_field(type: 'shared_folders', real_path: sh_path, field: field, value: value)['id']
|
579
|
+
end
|
580
|
+
when :user
|
581
|
+
sh_id = instance_identifier do |field, value|
|
582
|
+
lookup_entity_by_field(type: 'shared_folders', real_path: sh_path, field: field, value: value)['id']
|
583
|
+
end
|
584
|
+
user_path = "#{sh_path}/#{sh_id}/custom_access_users"
|
585
|
+
return entity_action(adm_api, user_path, item_list_key: 'users') do |field, value|
|
586
|
+
lookup_entity_by_field(type: 'users', real_path: user_path, field: field, value: value)['id']
|
587
|
+
end
|
588
|
+
|
589
|
+
end
|
590
|
+
when :browse
|
591
|
+
return browse_folder("#{res_path}/#{instance_identifier}/browse")
|
592
|
+
when :invite_external_collaborator
|
593
|
+
shared_inbox_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value, query: res_id_query)['id']}
|
594
|
+
creation_payload = value_create_modify(command: res_command, type: [Hash, String])
|
595
|
+
creation_payload = {'email_address' => creation_payload} if creation_payload.is_a?(String)
|
596
|
+
res_path = "#{res_type}/#{shared_inbox_id}/external_collaborator"
|
597
|
+
result = adm_api.create(res_path, creation_payload)[:data]
|
598
|
+
formatter.display_status(result['message'])
|
599
|
+
result = lookup_entity_by_field(
|
600
|
+
type: 'members',
|
601
|
+
real_path: "#{res_type}/#{shared_inbox_id}/members",
|
602
|
+
value: creation_payload['email_address'],
|
603
|
+
query: {})
|
604
|
+
return {type: :single_object, data: result}
|
605
|
+
when :members, :saml_groups
|
606
|
+
res_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value, query: res_id_query)['id']}
|
607
|
+
res_prefix = "#{res_type}/#{res_id}"
|
608
|
+
res_path = "#{res_prefix}/#{res_command}"
|
609
|
+
list_key = res_command.to_s
|
610
|
+
list_key = 'groups' if res_command.eql?(:saml_groups)
|
611
|
+
sub_command = options.get_next_command(%i[create list modify delete])
|
612
|
+
if sub_command.eql?(:create) && options.get_option(:value).nil?
|
613
|
+
raise "use option 'value' to provide saml group_id and access (refer to API)" unless res_command.eql?(:members)
|
614
|
+
# first arg is one user name or list of users
|
615
|
+
users = options.get_next_argument('user id, %name:, or Array')
|
616
|
+
users = [users] unless users.is_a?(Array)
|
617
|
+
users = users.map do |user|
|
618
|
+
if (m = user.match(REGEX_LOOKUP_ID_BY_FIELD))
|
619
|
+
lookup_entity_by_field(
|
620
|
+
type: 'accounts',
|
621
|
+
field: m[1],
|
622
|
+
value: ExtendedValue.instance.evaluate(m[2]),
|
623
|
+
query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})})['id']
|
624
|
+
else
|
625
|
+
# it's the user id (not member id...)
|
626
|
+
user
|
627
|
+
end
|
628
|
+
end
|
629
|
+
access = options.get_next_argument('level', mandatory: false, expected: %i[submit_only standard shared_inbox_admin], default: :standard)
|
630
|
+
# TODO: unshift to command line parameters instead of using deprecated option "value"
|
631
|
+
options.set_option(:value, {user: users.map{|u|{id: u, access: access}}})
|
632
|
+
end
|
633
|
+
return entity_command(sub_command, adm_api, res_path, item_list_key: list_key) do |field, value|
|
634
|
+
lookup_entity_by_field(
|
635
|
+
type: 'accounts',
|
636
|
+
field: field,
|
637
|
+
value: value,
|
638
|
+
query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})})['id']
|
639
|
+
end
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
def execute_admin
|
644
|
+
command = options.get_next_command(%i[configuration smtp resource events clean_deleted].concat(ADMIN_RESOURCES).freeze)
|
645
|
+
case command
|
646
|
+
when :resource
|
647
|
+
# resource is will be deprecated
|
648
|
+
Log.log.warn('resource command is deprecated (4.18), directly use the specific command instead')
|
649
|
+
return execute_resource(options.get_next_command(ADMIN_RESOURCES))
|
650
|
+
when *ADMIN_RESOURCES
|
651
|
+
return execute_resource(command)
|
652
|
+
when :clean_deleted
|
653
|
+
delete_data = value_create_modify(command: command, default: {days_before_deleting_package_records: 365})
|
654
|
+
res = @api_v5.create('internal/packages/clean_deleted', delete_data)
|
655
|
+
return {type: :single_object, data: res[:data]}
|
656
|
+
when :events
|
657
|
+
event_type = options.get_next_command(%i[application webhook])
|
658
|
+
case event_type
|
659
|
+
when :application
|
660
|
+
return {type: :object_list, data: list_entities(type: 'application_events'), fields: %w[event_type created_at application user.name]}
|
661
|
+
when :webhook
|
662
|
+
return {type: :object_list, data: list_entities(type: 'all_webhooks_events', item_list_key: 'events')}
|
663
|
+
end
|
664
|
+
when :configuration
|
665
|
+
conf_path = 'configuration'
|
666
|
+
conf_cmd = options.get_next_command(%i[show modify])
|
667
|
+
case conf_cmd
|
668
|
+
when :show
|
669
|
+
return { type: :single_object, data: @api_v5.read(conf_path)[:data] }
|
670
|
+
when :modify
|
671
|
+
return { type: :single_object, data: @api_v5.update(conf_path, value_create_modify(command: conf_cmd))[:data] }
|
672
|
+
end
|
673
|
+
when :smtp
|
674
|
+
smtp_path = 'configuration/smtp'
|
675
|
+
smtp_cmd = options.get_next_command(%i[show create modify delete test])
|
676
|
+
case smtp_cmd
|
677
|
+
when :show
|
678
|
+
return { type: :single_object, data: @api_v5.read(smtp_path)[:data] }
|
679
|
+
when :create
|
680
|
+
return { type: :single_object, data: @api_v5.create(smtp_path, value_create_modify(command: smtp_cmd))[:data] }
|
681
|
+
when :modify
|
682
|
+
return { type: :single_object, data: @api_v5.update(smtp_path, value_create_modify(command: smtp_cmd))[:data] }
|
683
|
+
when :delete
|
684
|
+
@api_v5.delete(smtp_path)[:data]
|
685
|
+
return Main.result_status('SMTP configuration deleted')
|
686
|
+
when :test
|
687
|
+
test_data = options.get_next_argument('Email or test data, see API')
|
688
|
+
test_data = {test_email_recipient: test_data} if test_data.is_a?(String)
|
689
|
+
creation = @api_v5.create(File.join(smtp_path, 'test'), test_data)[:data]
|
690
|
+
result = wait_for_job(creation['job_id'])
|
691
|
+
result['serialized_args'] = JSON.parse(result['serialized_args']) rescue result['serialized_args']
|
692
|
+
return { type: :single_object, data: result }
|
693
|
+
end
|
694
|
+
end
|
514
695
|
end
|
515
696
|
|
516
697
|
ACTIONS = %i[health version user bearer_token packages shared_folders admin gateway postprocessing invitations].freeze
|
@@ -546,7 +727,7 @@ module Aspera
|
|
546
727
|
end
|
547
728
|
end
|
548
729
|
when :bearer_token
|
549
|
-
return {type: :text, data: @api_v5.
|
730
|
+
return {type: :text, data: @api_v5.oauth.token}
|
550
731
|
when :packages
|
551
732
|
return package_action
|
552
733
|
when :shared_folders
|
@@ -566,117 +747,7 @@ module Aspera
|
|
566
747
|
return browse_folder("nodes/#{node['node_id']}/shared_folders/#{shared_folder_id}/browse")
|
567
748
|
end
|
568
749
|
when :admin
|
569
|
-
|
570
|
-
when :resource
|
571
|
-
res_type = options.get_next_command(ADMIN_RESOURCES)
|
572
|
-
res_path = list_key = res_type.to_s
|
573
|
-
id_as_arg = false
|
574
|
-
display_fields = nil
|
575
|
-
adm_api = @api_v5
|
576
|
-
special_query = :default
|
577
|
-
available_commands = [].concat(Plugin::ALL_OPS)
|
578
|
-
case res_type
|
579
|
-
when :metadata_profiles
|
580
|
-
res_path = 'configuration/metadata_profiles'
|
581
|
-
list_key = 'profiles'
|
582
|
-
when :alternate_addresses
|
583
|
-
res_path = 'configuration/alternate_addresses'
|
584
|
-
when :email_notifications
|
585
|
-
list_key = false
|
586
|
-
id_as_arg = 'type'
|
587
|
-
when :accounts
|
588
|
-
display_fields = Formatter.all_but('user_profile_data_attributes')
|
589
|
-
when :oauth_clients
|
590
|
-
display_fields = Formatter.all_but('public_key')
|
591
|
-
adm_api = Rest.new(**@api_v5.params.merge(base_url: "#{@faspex5_api_base_url}/#{PATH_AUTH}"))
|
592
|
-
when :shared_inboxes, :workgroups
|
593
|
-
available_commands.push(:members, :saml_groups, :invite_external_collaborator)
|
594
|
-
special_query = {'all': true}
|
595
|
-
when :nodes
|
596
|
-
available_commands.push(:shared_folders, :browse)
|
597
|
-
end
|
598
|
-
res_command = options.get_next_command(available_commands)
|
599
|
-
case res_command
|
600
|
-
when *Plugin::ALL_OPS
|
601
|
-
return entity_command(res_command, adm_api, res_path, item_list_key: list_key, display_fields: display_fields, id_as_arg: id_as_arg) do |field, value|
|
602
|
-
lookup_entity_by_field(
|
603
|
-
type: res_type, real_path: res_path, field: field, value: value, query: special_query)['id']
|
604
|
-
end
|
605
|
-
when :shared_folders
|
606
|
-
node_id = instance_identifier do |field, value|
|
607
|
-
lookup_entity_by_field(type: res_type.to_s, field: field, value: value)['id']
|
608
|
-
end
|
609
|
-
sh_path = "#{res_path}/#{node_id}/shared_folders"
|
610
|
-
return entity_action(adm_api, sh_path, item_list_key: 'shared_folders') do |field, value|
|
611
|
-
lookup_entity_by_field(
|
612
|
-
type: 'shared_folders', real_path: sh_path, field: field, value: value)['id']
|
613
|
-
end
|
614
|
-
when :browse
|
615
|
-
return browse_folder("#{res_path}/#{instance_identifier}/browse")
|
616
|
-
when :invite_external_collaborator
|
617
|
-
shared_inbox_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value)['id']}
|
618
|
-
creation_payload = value_create_modify(command: res_command, type: [Hash, String])
|
619
|
-
creation_payload = {'email_address' => creation_payload} if creation_payload.is_a?(String)
|
620
|
-
res_path = "#{res_type}/#{shared_inbox_id}/external_collaborator"
|
621
|
-
result = adm_api.create(res_path, creation_payload)[:data]
|
622
|
-
formatter.display_status(result['message'])
|
623
|
-
result = lookup_entity_by_field(
|
624
|
-
type: 'members', real_path: "#{res_type}/#{shared_inbox_id}/members", value: creation_payload['email_address'],
|
625
|
-
query: {})
|
626
|
-
return {type: :single_object, data: result}
|
627
|
-
when :members, :saml_groups
|
628
|
-
res_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value)['id']}
|
629
|
-
res_prefix = "#{res_type}/#{res_id}"
|
630
|
-
res_path = "#{res_prefix}/#{res_command}"
|
631
|
-
list_key = res_command.to_s
|
632
|
-
list_key = 'groups' if res_command.eql?(:saml_groups)
|
633
|
-
sub_command = options.get_next_command(%i[create list modify delete])
|
634
|
-
if sub_command.eql?(:create) && options.get_option(:value).nil?
|
635
|
-
raise "use option 'value' to provide saml group_id and access (refer to API)" unless res_command.eql?(:members)
|
636
|
-
# first arg is one user name or list of users
|
637
|
-
users = options.get_next_argument('user id, or email, or list of')
|
638
|
-
users = [users] unless users.is_a?(Array)
|
639
|
-
users = users.map do |user|
|
640
|
-
if (m = user.match(REGEX_LOOKUP_ID_BY_FIELD))
|
641
|
-
lookup_entity_by_field(
|
642
|
-
type: 'accounts', field: m[1], value: m[2],
|
643
|
-
query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})})['id']
|
644
|
-
else
|
645
|
-
# it's the user id (not member id...)
|
646
|
-
user
|
647
|
-
end
|
648
|
-
end
|
649
|
-
access = options.get_next_argument('level', mandatory: false, expected: %i[submit_only standard shared_inbox_admin], default: :standard)
|
650
|
-
# TODO: unshift to command line parameters instead of using deprecated option "value"
|
651
|
-
options.set_option(:value, {user: users.map{|u|{id: u, access: access}}})
|
652
|
-
end
|
653
|
-
return entity_command(sub_command, adm_api, res_path, item_list_key: list_key) do |field, value|
|
654
|
-
lookup_entity_by_field(
|
655
|
-
type: 'accounts', field: field, value: value,
|
656
|
-
query: {type: Rest.array_params(%w{local_user saml_user self_registered_user external_user})})['id']
|
657
|
-
end
|
658
|
-
end
|
659
|
-
when :smtp
|
660
|
-
smtp_path = 'configuration/smtp'
|
661
|
-
smtp_cmd = options.get_next_command(%i[show create modify delete test])
|
662
|
-
case smtp_cmd
|
663
|
-
when :show
|
664
|
-
return { type: :single_object, data: @api_v5.read(smtp_path)[:data] }
|
665
|
-
when :create
|
666
|
-
return { type: :single_object, data: @api_v5.create(smtp_path, value_create_modify(command: smtp_cmd))[:data] }
|
667
|
-
when :modify
|
668
|
-
return { type: :single_object, data: @api_v5.update(smtp_path, value_create_modify(command: smtp_cmd))[:data] }
|
669
|
-
when :delete
|
670
|
-
return { type: :single_object, data: @api_v5.delete(smtp_path)[:data] }
|
671
|
-
when :test
|
672
|
-
test_data = options.get_next_argument('Email or test data, see API')
|
673
|
-
test_data = {test_email_recipient: test_data} if test_data.is_a?(String)
|
674
|
-
creation = @api_v5.create(File.join(smtp_path, 'test'), test_data)[:data]
|
675
|
-
result = wait_for_job(creation['job_id'])
|
676
|
-
result['serialized_args'] = JSON.parse(result['serialized_args']) rescue result['serialized_args']
|
677
|
-
return { type: :single_object, data: result }
|
678
|
-
end
|
679
|
-
end
|
750
|
+
return execute_admin
|
680
751
|
when :invitations
|
681
752
|
invitation_endpoint = 'invitations'
|
682
753
|
invitation_command = options.get_next_command(%i[resend].concat(Plugin::ALL_OPS))
|
@@ -692,7 +763,9 @@ module Aspera
|
|
692
763
|
else
|
693
764
|
return entity_command(
|
694
765
|
invitation_command, @api_v5, invitation_endpoint, item_list_key: invitation_endpoint,
|
695
|
-
display_fields: %w[id public recipient_type recipient_name email_address])
|
766
|
+
display_fields: %w[id public recipient_type recipient_name email_address]) do |field, value|
|
767
|
+
lookup_entity_by_field(type: invitation_endpoint, field: field, value: value, query: {})['id']
|
768
|
+
end
|
696
769
|
end
|
697
770
|
when :gateway
|
698
771
|
require 'aspera/faspex_gw'
|
@@ -714,9 +787,9 @@ module Aspera
|
|
714
787
|
server.mount(uri.path, Faspex4PostProcServlet, parameters[:processing])
|
715
788
|
server.start
|
716
789
|
return Main.result_status('Gateway terminated')
|
717
|
-
end
|
718
|
-
end
|
719
|
-
end
|
720
|
-
end
|
721
|
-
end
|
722
|
-
end
|
790
|
+
end
|
791
|
+
end
|
792
|
+
end
|
793
|
+
end
|
794
|
+
end
|
795
|
+
end
|