aspera-cli 4.22.0 → 4.24.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 +0 -0
- data/CHANGELOG.md +405 -364
- data/CONTRIBUTING.md +86 -29
- data/README.md +1856 -961
- data/bin/ascli +2 -1
- data/bin/asession +4 -4
- data/lib/aspera/agent/base.rb +4 -0
- data/lib/aspera/agent/connect.rb +20 -18
- data/lib/aspera/agent/desktop.rb +14 -11
- data/lib/aspera/agent/direct.rb +39 -31
- data/lib/aspera/agent/httpgw.rb +2 -2
- data/lib/aspera/agent/node.rb +9 -11
- data/lib/aspera/agent/transferd.rb +18 -11
- data/lib/aspera/api/aoc.rb +53 -43
- data/lib/aspera/api/cos_node.rb +7 -5
- data/lib/aspera/api/httpgw.rb +23 -22
- data/lib/aspera/api/node.rb +104 -22
- data/lib/aspera/ascmd.rb +35 -21
- data/lib/aspera/ascp/installation.rb +43 -43
- data/lib/aspera/ascp/management.rb +5 -4
- data/lib/aspera/assert.rb +55 -24
- data/lib/aspera/cli/basic_auth_plugin.rb +8 -7
- data/lib/aspera/cli/error.rb +1 -1
- data/lib/aspera/cli/extended_value.rb +28 -29
- data/lib/aspera/cli/formatter.rb +191 -168
- data/lib/aspera/cli/hints.rb +38 -4
- data/lib/aspera/cli/main.rb +139 -108
- data/lib/aspera/cli/manager.rb +51 -31
- data/lib/aspera/cli/plugin.rb +149 -78
- data/lib/aspera/cli/plugin_factory.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +217 -88
- data/lib/aspera/cli/plugins/ats.rb +15 -13
- data/lib/aspera/cli/plugins/config.rb +105 -227
- data/lib/aspera/cli/plugins/console.rb +49 -18
- data/lib/aspera/cli/plugins/cos.rb +4 -4
- data/lib/aspera/cli/plugins/faspex.rb +45 -51
- data/lib/aspera/cli/plugins/faspex5.rb +162 -163
- data/lib/aspera/cli/plugins/faspio.rb +6 -5
- data/lib/aspera/cli/plugins/httpgw.rb +2 -2
- data/lib/aspera/cli/plugins/node.rb +233 -247
- data/lib/aspera/cli/plugins/orchestrator.rb +10 -14
- data/lib/aspera/cli/plugins/preview.rb +26 -29
- data/lib/aspera/cli/plugins/server.rb +29 -28
- data/lib/aspera/cli/plugins/shares.rb +40 -28
- data/lib/aspera/cli/sync_actions.rb +101 -80
- data/lib/aspera/cli/transfer_agent.rb +55 -58
- data/lib/aspera/cli/transfer_progress.rb +29 -20
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +160 -0
- data/lib/aspera/colors.rb +13 -8
- data/lib/aspera/command_line_builder.rb +28 -22
- data/lib/aspera/command_line_converter.rb +31 -0
- data/lib/aspera/data_repository.rb +1 -0
- data/lib/aspera/environment.rb +144 -100
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/faspex_postproc.rb +3 -2
- data/lib/aspera/hash_ext.rb +1 -1
- data/lib/aspera/id_generator.rb +10 -10
- data/lib/aspera/keychain/base.rb +18 -0
- data/lib/aspera/keychain/encrypted_hash.rb +6 -12
- data/lib/aspera/keychain/factory.rb +9 -3
- data/lib/aspera/keychain/hashicorp_vault.rb +9 -6
- data/lib/aspera/keychain/macos_security.rb +13 -13
- data/lib/aspera/log.rb +70 -20
- data/lib/aspera/nagios.rb +5 -6
- data/lib/aspera/node_simulator.rb +12 -7
- data/lib/aspera/oauth/base.rb +6 -2
- data/lib/aspera/oauth/factory.rb +25 -18
- data/lib/aspera/oauth/jwt.rb +13 -1
- data/lib/aspera/oauth/url_json.rb +3 -3
- data/lib/aspera/oauth/web.rb +5 -3
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/file_types.rb +43 -35
- data/lib/aspera/preview/generator.rb +26 -13
- data/lib/aspera/preview/terminal.rb +10 -7
- data/lib/aspera/preview/utils.rb +11 -9
- data/lib/aspera/products/connect.rb +2 -1
- data/lib/aspera/products/desktop.rb +1 -1
- data/lib/aspera/products/other.rb +2 -2
- data/lib/aspera/products/transferd.rb +8 -6
- data/lib/aspera/proxy_auto_config.rb +1 -1
- data/lib/aspera/rest.rb +46 -28
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +1 -0
- data/lib/aspera/resumer.rb +1 -1
- data/lib/aspera/secret_hider.rb +46 -40
- data/lib/aspera/ssh.rb +14 -4
- data/lib/aspera/sync/args.schema.yaml +102 -0
- data/lib/aspera/sync/conf.schema.yaml +701 -0
- data/lib/aspera/sync/database.rb +83 -0
- data/lib/aspera/{transfer/sync.rb → sync/operations.rb} +145 -68
- data/lib/aspera/temp_file_manager.rb +4 -2
- data/lib/aspera/timer_limiter.rb +7 -5
- data/lib/aspera/transfer/error.rb +1 -1
- data/lib/aspera/transfer/error_info.rb +1 -2
- data/lib/aspera/transfer/faux_file.rb +11 -10
- data/lib/aspera/transfer/parameters.rb +6 -5
- data/lib/aspera/transfer/spec.rb +15 -1
- data/lib/aspera/transfer/spec.schema.yaml +316 -293
- data/lib/aspera/transfer/spec_doc.rb +34 -16
- data/lib/aspera/transfer/uri.rb +5 -5
- data/lib/aspera/uri_reader.rb +14 -10
- data/lib/aspera/web_auth.rb +2 -2
- data/lib/aspera/web_server_simple.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +15 -15
- metadata.gz.sig +0 -0
- data/examples/dascli +0 -30
- data/examples/get_proto_file.rb +0 -8
- data/examples/proxy.pac +0 -60
- data/lib/aspera/transfer/convert.rb +0 -29
- data/lib/aspera/transfer/sync_instance.schema.yaml +0 -13
- data/lib/aspera/transfer/sync_session.schema.yaml +0 -79
@@ -44,16 +44,18 @@ module Aspera
|
|
44
44
|
application
|
45
45
|
client_registration_token
|
46
46
|
client_access_key
|
47
|
-
kms_profile
|
47
|
+
kms_profile
|
48
|
+
].freeze
|
48
49
|
# query to list fully received packages
|
49
50
|
PACKAGE_RECEIVED_BASE_QUERY = {
|
50
51
|
'archived' => false,
|
51
52
|
'has_content' => true,
|
52
53
|
'received' => true,
|
53
|
-
'completed' => true
|
54
|
+
'completed' => true
|
55
|
+
}.freeze
|
56
|
+
PACKAGE_LIST_DEFAULT_FIELDS = %w[id name created_at files_completed bytes_transferred].freeze
|
54
57
|
# options and parameters for Api::AoC.new
|
55
58
|
OPTIONS_NEW = %i[url auth client_id client_secret scope redirect_uri private_key passphrase username password workspace].freeze
|
56
|
-
PACKAGE_LIST_DEFAULT_FIELDS = %w[id name created_at files_completed bytes_transferred].freeze
|
57
59
|
|
58
60
|
private_constant :REDIRECT_LOCALHOST, :STD_AUTH_TYPES, :ADMIN_OBJECTS, :PACKAGE_RECEIVED_BASE_QUERY, :OPTIONS_NEW, :PACKAGE_LIST_DEFAULT_FIELDS
|
59
61
|
class << self
|
@@ -67,12 +69,12 @@ module Aspera
|
|
67
69
|
# only org provided ?
|
68
70
|
base_url = "#{base_url}.#{Api::AoC::SAAS_DOMAIN_PROD}" unless base_url.include?('.')
|
69
71
|
# AoC is only https
|
70
|
-
return
|
72
|
+
return unless base_url.start_with?('https://')
|
71
73
|
res_http = Rest.new(base_url: base_url, redirect_max: 0).call(operation: 'GET', subpath: 'auth/ping', return_error: true)[:http]
|
72
|
-
return
|
74
|
+
return if res_http['Location'].nil?
|
73
75
|
redirect_uri = URI.parse(res_http['Location'])
|
74
76
|
od = Api::AoC.split_org_domain(URI.parse(base_url))
|
75
|
-
return
|
77
|
+
return unless redirect_uri.path.end_with?("oauth2/#{od[:organization]}/login")
|
76
78
|
# either in standard domain, or product name in page
|
77
79
|
return {
|
78
80
|
version: Api::AoC.saas_url?(base_url) ? 'SaaS' : 'Self-managed',
|
@@ -150,14 +152,14 @@ module Aspera
|
|
150
152
|
formatter.display_status('We will use web authentication to bootstrap.')
|
151
153
|
auto_set_pub_key = true
|
152
154
|
auto_set_jwt = true
|
153
|
-
|
155
|
+
Aspera.error_not_implemented
|
154
156
|
# aoc_api.oauth.grant_method = :web
|
155
157
|
# aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN
|
156
158
|
# aoc_api.oauth.specific_parameters[:redirect_uri] = REDIRECT_LOCALHOST
|
157
159
|
end
|
158
160
|
myself = object.aoc_api.read('self')
|
159
161
|
if auto_set_pub_key
|
160
|
-
Aspera.assert(myself['public_key'].empty?,
|
162
|
+
Aspera.assert(myself['public_key'].empty?, type: Cli::Error){'Public key is already set in profile (use --override=yes)'} unless option_override
|
161
163
|
formatter.display_status('Updating profile with the public key.')
|
162
164
|
aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
|
163
165
|
end
|
@@ -181,6 +183,38 @@ module Aspera
|
|
181
183
|
test_args: 'user profile show'
|
182
184
|
}
|
183
185
|
end
|
186
|
+
|
187
|
+
# @param base [String] Base folder path
|
188
|
+
# @return [String] Folder path that does jot exist, with possible .<number> extension
|
189
|
+
def next_available_folder(base, always: false)
|
190
|
+
counter = always ? 1 : 0
|
191
|
+
loop do
|
192
|
+
result = counter.zero? ? base : "#{base}.#{counter}"
|
193
|
+
return result unless Dir.exist?(result)
|
194
|
+
counter += 1
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get folder path that does not exist
|
199
|
+
# If it exists, an extension is added
|
200
|
+
# or a sequential number if extension == :seq
|
201
|
+
# @param folder [String] base folder
|
202
|
+
def unique_folder(folder, extension: nil, always: false)
|
203
|
+
case extension
|
204
|
+
when nil
|
205
|
+
folder
|
206
|
+
when :seq
|
207
|
+
# reuse helper
|
208
|
+
next_available_folder(folder, always: always)
|
209
|
+
else
|
210
|
+
if Dir.exist?(folder) || always
|
211
|
+
# NOTE: it might already exist
|
212
|
+
"#{folder}.#{Environment.instance.sanitized_filename(extension)}"
|
213
|
+
else
|
214
|
+
folder
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
184
218
|
end
|
185
219
|
|
186
220
|
def initialize(**_)
|
@@ -191,22 +225,29 @@ module Aspera
|
|
191
225
|
options.declare(:auth, 'OAuth type of authentication', values: STD_AUTH_TYPES, default: :jwt)
|
192
226
|
options.declare(:client_id, 'OAuth API client identifier')
|
193
227
|
options.declare(:client_secret, 'OAuth API client secret')
|
194
|
-
options.declare(:scope, 'OAuth scope for AoC API calls'
|
228
|
+
options.declare(:scope, 'OAuth scope for AoC API calls')
|
195
229
|
options.declare(:redirect_uri, 'OAuth API client redirect URI')
|
196
230
|
options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
|
197
231
|
options.declare(:passphrase, 'RSA private key passphrase', types: String)
|
198
232
|
options.declare(:workspace, 'Name of workspace', types: [String, NilClass], default: Api::AoC::DEFAULT_WORKSPACE)
|
199
233
|
options.declare(:new_user_option, 'New user creation option for unknown package recipients', types: Hash)
|
200
234
|
options.declare(:validate_metadata, 'Validate shared inbox metadata', values: :bool, default: true)
|
235
|
+
options.declare(:package_folder, 'Field of package to use as folder name, or @none:', types: [String, NilClass])
|
201
236
|
options.parse_options!
|
202
237
|
# add node plugin options (for manual)
|
203
238
|
Node.declare_options(options)
|
204
239
|
end
|
205
240
|
|
206
|
-
def api_from_options(
|
207
|
-
create_values = {
|
241
|
+
def api_from_options(aoc_base_path)
|
242
|
+
create_values = OPTIONS_NEW.each_with_object({
|
243
|
+
subpath: aoc_base_path,
|
244
|
+
secret_finder: config
|
245
|
+
}) do |i, m|
|
246
|
+
m[i] = options.get_option(i) unless options.get_option(i).nil?
|
247
|
+
end
|
248
|
+
create_values[:scope] = Api::AoC::SCOPE_FILES_USER if create_values[:scope].nil?
|
208
249
|
# create an API object with the same options, but with a different subpath
|
209
|
-
return Api::AoC.new(**
|
250
|
+
return Api::AoC.new(**create_values)
|
210
251
|
rescue ArgumentError => e
|
211
252
|
if (m = e.message.match(/missing keyword: :(.*)$/))
|
212
253
|
raise Cli::Error, "Missing option: #{m[1]}"
|
@@ -249,7 +290,7 @@ module Aspera
|
|
249
290
|
# @return identifier
|
250
291
|
def get_resource_id_from_args(resource_class_path)
|
251
292
|
return instance_identifier do |field, value|
|
252
|
-
Aspera.assert(field.eql?('name'),
|
293
|
+
Aspera.assert(field.eql?('name'), type: Cli::BadArgument){'only selection by name is supported'}
|
253
294
|
aoc_api.lookup_by_name(resource_class_path, value)['id']
|
254
295
|
end
|
255
296
|
end
|
@@ -262,7 +303,7 @@ module Aspera
|
|
262
303
|
# Call block with same query using paging and response information
|
263
304
|
# block must return a hash with :data and :http keys
|
264
305
|
# @return [Hash] {items: , total: }
|
265
|
-
def api_call_paging(base_query={})
|
306
|
+
def api_call_paging(base_query = {})
|
266
307
|
Aspera.assert_type(base_query, Hash){'query'}
|
267
308
|
Aspera.assert(block_given?)
|
268
309
|
# set default large page if user does not specify own parameters. AoC Caps to 1000 anyway
|
@@ -298,7 +339,7 @@ module Aspera
|
|
298
339
|
|
299
340
|
# read using the query and paging
|
300
341
|
# @return [Hash] {data: , total: }
|
301
|
-
def api_read_all(resource_class_path, base_query={})
|
342
|
+
def api_read_all(resource_class_path, base_query = {})
|
302
343
|
return api_call_paging(base_query) do |query|
|
303
344
|
aoc_api.call(operation: 'GET', subpath: resource_class_path, headers: {'Accept' => Rest::MIME_JSON}, query: query)
|
304
345
|
end
|
@@ -324,7 +365,7 @@ module Aspera
|
|
324
365
|
def resolve_dropbox_name_default_ws_id(query)
|
325
366
|
if query.key?('dropbox_name')
|
326
367
|
# convenience: specify name instead of id
|
327
|
-
raise 'Use field dropbox_name or dropbox_id, not both' if query.key?('dropbox_id')
|
368
|
+
raise BadArgument, 'Use field dropbox_name or dropbox_id, not both' if query.key?('dropbox_id')
|
328
369
|
# TODO : craft a query that looks for dropbox only in current workspace
|
329
370
|
query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query.delete('dropbox_name'))['id']
|
330
371
|
end
|
@@ -333,6 +374,8 @@ module Aspera
|
|
333
374
|
query['exclude_dropbox_packages'] = !query.key?('dropbox_id') unless query.key?('exclude_dropbox_packages')
|
334
375
|
end
|
335
376
|
|
377
|
+
# List all packages according to `query` option.
|
378
|
+
# @param <none>
|
336
379
|
# @return [Hash] {items,total} with all packages according to combination of user's query and default query
|
337
380
|
def list_all_packages_with_query
|
338
381
|
query = query_read_delete(default: {})
|
@@ -354,7 +397,7 @@ module Aspera
|
|
354
397
|
**workspace_id_hash(name: true)
|
355
398
|
)
|
356
399
|
file_id = top_node_api.read("access_keys/#{top_node_api.app_info[:node_info]['access_key']}")['root_file_id'] if file_id.nil?
|
357
|
-
node_plugin = Node.new(
|
400
|
+
node_plugin = Node.new(context: context, api: top_node_api)
|
358
401
|
case command_repo
|
359
402
|
when *Node::COMMANDS_GEN4
|
360
403
|
return node_plugin.execute_command_gen4(command_repo, file_id)
|
@@ -393,8 +436,9 @@ module Aspera
|
|
393
436
|
return Main.result_transfer(transfer.start(server_apfid[:api].transfer_spec_gen4(
|
394
437
|
server_apfid[:file_id],
|
395
438
|
client_direction,
|
396
|
-
add_ts
|
397
|
-
|
439
|
+
add_ts
|
440
|
+
)))
|
441
|
+
else Aspera.error_unexpected_value(command_repo){'command'}
|
398
442
|
end
|
399
443
|
Aspera.error_unreachable_line
|
400
444
|
end
|
@@ -443,7 +487,9 @@ module Aspera
|
|
443
487
|
default_fields.push('app_type', 'app_name', 'available', 'direct_authorizations_allowed', 'workspace_authorizations_allowed')
|
444
488
|
when :client, :client_access_key, :dropbox, :group, :package, :saml_configuration, :workspace then default_fields.push('name')
|
445
489
|
when :client_registration_token then default_fields.push('value', 'data.client_subject_scopes', 'created_at')
|
446
|
-
when :contact
|
490
|
+
when :contact
|
491
|
+
default_fields = %w[source_type source_id name email]
|
492
|
+
default_query = {'include_only_user_personal_contacts' => true} if aoc_api.oauth.scope == Api::AoC::SCOPE_FILES_USER
|
447
493
|
when :node then default_fields.push('name', 'host', 'access_key')
|
448
494
|
when :operation then default_fields = nil
|
449
495
|
when :short_link then default_fields.push('short_url', 'data.url_token_data.purpose')
|
@@ -459,12 +505,12 @@ module Aspera
|
|
459
505
|
return Main.result_single_object(object, fields: fields)
|
460
506
|
when :modify
|
461
507
|
changes = options.get_next_argument('properties', validation: Hash)
|
462
|
-
return do_bulk_operation(command: command,
|
508
|
+
return do_bulk_operation(command: command, values: res_id) do |one_id|
|
463
509
|
aoc_api.update("#{resource_class_path}/#{one_id}", changes)
|
464
510
|
{'id' => one_id}
|
465
511
|
end
|
466
512
|
when :delete
|
467
|
-
return do_bulk_operation(command: command,
|
513
|
+
return do_bulk_operation(command: command, values: res_id) do |one_id|
|
468
514
|
aoc_api.delete("#{resource_class_path}/#{one_id}")
|
469
515
|
{'id' => one_id}
|
470
516
|
end
|
@@ -486,8 +532,8 @@ module Aspera
|
|
486
532
|
ADMIN_ACTIONS = %i[ats resource usage_reports analytics subscription auth_providers].concat(ADMIN_OBJECTS).freeze
|
487
533
|
|
488
534
|
def execute_admin_action
|
489
|
-
#
|
490
|
-
aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN
|
535
|
+
# default scope to admin
|
536
|
+
aoc_api.oauth.scope = Api::AoC::SCOPE_FILES_ADMIN if options.get_option(:scope).nil?
|
491
537
|
command_admin = options.get_next_command(ADMIN_ACTIONS)
|
492
538
|
case command_admin
|
493
539
|
when :resource
|
@@ -501,7 +547,7 @@ module Aspera
|
|
501
547
|
when :list
|
502
548
|
return result_list('admin/auth_providers')
|
503
549
|
when :update
|
504
|
-
|
550
|
+
Aspera.error_not_implemented
|
505
551
|
end
|
506
552
|
when :subscription
|
507
553
|
org = aoc_api.read('organization')
|
@@ -603,12 +649,16 @@ module Aspera
|
|
603
649
|
# cspell:enable
|
604
650
|
result = bss_graphql.create(
|
605
651
|
nil,
|
606
|
-
{
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
652
|
+
{
|
653
|
+
query: graphql_query,
|
654
|
+
variables: {
|
655
|
+
organization_id: org['id'],
|
656
|
+
aggregate: aggregate,
|
657
|
+
startDate: start_date,
|
658
|
+
endDate: end_date
|
659
|
+
}
|
660
|
+
}
|
661
|
+
)['data']
|
612
662
|
return Main.result_single_object(result['aoc'])
|
613
663
|
end
|
614
664
|
when :ats
|
@@ -616,13 +666,13 @@ module Aspera
|
|
616
666
|
base_url: "#{aoc_api.base_url}/admin/ats/pub/v1",
|
617
667
|
auth: {scope: Api::AoC::SCOPE_FILES_ADMIN_USER}
|
618
668
|
}))
|
619
|
-
return Ats.new(
|
669
|
+
return Ats.new(context: context).execute_action_gen(ats_api)
|
620
670
|
when :analytics
|
621
671
|
analytics_api = Rest.new(**aoc_api.params.deep_merge({
|
622
672
|
base_url: "#{aoc_api.base_url.gsub('/api/v1', '')}/analytics/v2",
|
623
673
|
auth: {scope: Api::AoC::SCOPE_FILES_ADMIN_USER}
|
624
674
|
}))
|
625
|
-
command_analytics = options.get_next_command(%i[application_events transfers])
|
675
|
+
command_analytics = options.get_next_command(%i[application_events transfers files])
|
626
676
|
case command_analytics
|
627
677
|
when :application_events
|
628
678
|
event_type = command_analytics.to_s
|
@@ -630,15 +680,15 @@ module Aspera
|
|
630
680
|
return Main.result_object_list(events)
|
631
681
|
when :transfers
|
632
682
|
event_type = command_analytics.to_s
|
633
|
-
|
634
|
-
|
635
|
-
case
|
683
|
+
event_resource_type = options.get_next_argument('resource', accept_list: %i[organizations users nodes])
|
684
|
+
event_resource_id = options.get_next_argument("#{event_resource_type} identifier", mandatory: false) ||
|
685
|
+
case event_resource_type
|
636
686
|
when :organizations then aoc_api.current_user_info['organization_id']
|
637
687
|
when :users then aoc_api.current_user_info['id']
|
638
|
-
when :nodes then aoc_api.current_user_info['
|
688
|
+
when :nodes then aoc_api.current_user_info['read_only_home_node_id']
|
639
689
|
else Aspera.error_unreachable_line
|
640
690
|
end
|
641
|
-
filter =
|
691
|
+
filter = query_read_delete(default: {})
|
642
692
|
filter['limit'] ||= 100
|
643
693
|
if options.get_option(:once_only, mandatory: true)
|
644
694
|
aoc_api.context = :files
|
@@ -650,18 +700,17 @@ module Aspera
|
|
650
700
|
'aoc_ana_date',
|
651
701
|
options.get_option(:url, mandatory: true),
|
652
702
|
aoc_api.workspace[:name],
|
653
|
-
|
654
|
-
|
655
|
-
])
|
703
|
+
event_resource_type.to_s,
|
704
|
+
event_resource_id
|
705
|
+
])
|
706
|
+
)
|
656
707
|
start_date_time = saved_date.first
|
657
708
|
stop_date_time = Time.now.utc.strftime('%FT%T.%LZ')
|
658
|
-
# Log.log().error("start: #{start_date_time}")
|
659
|
-
# Log.log().error("end: #{stop_date_time}")
|
660
709
|
saved_date[0] = stop_date_time
|
661
710
|
filter['start_time'] = start_date_time unless start_date_time.nil?
|
662
711
|
filter['stop_time'] = stop_date_time
|
663
712
|
end
|
664
|
-
events = analytics_api.read("#{
|
713
|
+
events = analytics_api.read("#{event_resource_type}/#{event_resource_id}/#{event_type}", filter)[event_type]
|
665
714
|
start_date_persistency&.save
|
666
715
|
if !options.get_option(:notify_to).nil?
|
667
716
|
events.each do |tr_event|
|
@@ -669,6 +718,22 @@ module Aspera
|
|
669
718
|
end
|
670
719
|
end
|
671
720
|
return Main.result_object_list(events)
|
721
|
+
when :files
|
722
|
+
event_type = command_analytics.to_s
|
723
|
+
event_resource_type = options.get_next_argument('resource', accept_list: %i[organizations users nodes])
|
724
|
+
event_resource_id = instance_identifier(description: "#{event_resource_type} identifier")
|
725
|
+
event_resource_id =
|
726
|
+
case event_resource_type
|
727
|
+
when :organizations then aoc_api.current_user_info['organization_id']
|
728
|
+
when :users then aoc_api.current_user_info['id']
|
729
|
+
when :nodes then aoc_api.current_user_info['read_only_home_node_id']
|
730
|
+
else Aspera.error_unreachable_line
|
731
|
+
end if event_resource_id.empty?
|
732
|
+
event_uuid = instance_identifier(description: 'event uuid')
|
733
|
+
filter = query_read_delete(default: {})
|
734
|
+
filter['limit'] ||= 100
|
735
|
+
events = analytics_api.read("#{event_resource_type}/#{event_resource_id}/transfers/#{event_uuid}/#{event_type}", filter)[event_type]
|
736
|
+
return Main.result_object_list(events)
|
672
737
|
end
|
673
738
|
when :usage_reports
|
674
739
|
aoc_api.context = :files
|
@@ -692,20 +757,21 @@ module Aspera
|
|
692
757
|
when :private then 'shared_folder_auth_link'
|
693
758
|
else Aspera.error_unreachable_line
|
694
759
|
end
|
695
|
-
|
760
|
+
command = options.get_next_command(%i[create delete list show modify])
|
761
|
+
case command
|
696
762
|
when :create
|
697
|
-
|
763
|
+
entity_data = {
|
698
764
|
purpose: purpose_local,
|
699
765
|
user_selected_name: nil
|
700
766
|
}
|
701
767
|
case link_type
|
702
768
|
when :private
|
703
|
-
|
769
|
+
entity_data[:data] = shared_data
|
704
770
|
when :public
|
705
|
-
|
706
|
-
|
771
|
+
entity_data[:expires_at] = nil
|
772
|
+
entity_data[:password_enabled] = false
|
707
773
|
shared_data[:name] = ''
|
708
|
-
|
774
|
+
entity_data[:data] = {
|
709
775
|
aoc: true,
|
710
776
|
url_token_data: {
|
711
777
|
data: shared_data,
|
@@ -713,11 +779,17 @@ module Aspera
|
|
713
779
|
}
|
714
780
|
}
|
715
781
|
end
|
716
|
-
|
782
|
+
custom_data = value_create_modify(command: command, default: {})
|
783
|
+
if (pass = custom_data.delete('password'))
|
784
|
+
entity_data[:data][:url_token_data][:password] = pass
|
785
|
+
entity_data[:password_enabled] = true
|
786
|
+
end
|
787
|
+
entity_data.deep_merge!(custom_data)
|
788
|
+
result_create_short_link = aoc_api.create('short_links', entity_data)
|
717
789
|
# public: Creation: permission on node
|
718
790
|
yield(result_create_short_link['resource_id']) if block_given? && link_type.eql?(:public)
|
719
791
|
return Main.result_single_object(result_create_short_link)
|
720
|
-
when :list
|
792
|
+
when :list, :show
|
721
793
|
query = if link_type.eql?(:private)
|
722
794
|
shared_data
|
723
795
|
else
|
@@ -735,7 +807,31 @@ module Aspera
|
|
735
807
|
# embed: 'updated_by_user',
|
736
808
|
sort: '-created_at'
|
737
809
|
}
|
738
|
-
return result_list('short_links', fields: Formatter.all_but('data'), base_query: list_params)
|
810
|
+
return result_list('short_links', fields: Formatter.all_but('data'), base_query: list_params) if command.eql?(:list)
|
811
|
+
one_id = instance_identifier
|
812
|
+
found = api_read_all('short_links', list_params)[:items].find{ |item| item['id'].eql?(one_id)}
|
813
|
+
raise Cli::BadIdentifier.new('Short link', one_id) if found.nil?
|
814
|
+
return Main.result_single_object(found, fields: Formatter.all_but('data'))
|
815
|
+
when :modify
|
816
|
+
raise Cli::BadArgument, 'Only public links can be modified' unless link_type.eql?(:public)
|
817
|
+
node_file = shared_data.slice(:node_id, :file_id)
|
818
|
+
entity_data = {
|
819
|
+
data: {
|
820
|
+
url_token_data: {
|
821
|
+
data: node_file
|
822
|
+
}
|
823
|
+
},
|
824
|
+
json_query: node_file
|
825
|
+
}
|
826
|
+
one_id = instance_identifier
|
827
|
+
custom_data = value_create_modify(command: command, default: {})
|
828
|
+
if (pass = custom_data.delete('password'))
|
829
|
+
entity_data[:data][:url_token_data][:password] = pass
|
830
|
+
entity_data[:password_enabled] = true
|
831
|
+
end
|
832
|
+
entity_data.deep_merge!(custom_data)
|
833
|
+
aoc_api.update("short_links/#{one_id}", entity_data)
|
834
|
+
return Main.result_status('modified')
|
739
835
|
when :delete
|
740
836
|
one_id = instance_identifier
|
741
837
|
shared_data.delete(:workspace_id)
|
@@ -754,7 +850,7 @@ module Aspera
|
|
754
850
|
|
755
851
|
# @return persistency object if option `once_only` is used.
|
756
852
|
def package_persistency
|
757
|
-
return
|
853
|
+
return unless options.get_option(:once_only, mandatory: true)
|
758
854
|
# TODO: add query info to id
|
759
855
|
PersistencyActionOnce.new(
|
760
856
|
manager: persistency,
|
@@ -762,8 +858,9 @@ module Aspera
|
|
762
858
|
id: IdGenerator.from_list(
|
763
859
|
['aoc_recv',
|
764
860
|
options.get_option(:url, mandatory: true),
|
765
|
-
aoc_api.workspace[:id]
|
766
|
-
|
861
|
+
aoc_api.workspace[:id]].concat(aoc_api.additional_persistence_ids)
|
862
|
+
)
|
863
|
+
)
|
767
864
|
end
|
768
865
|
|
769
866
|
def reject_packages_from_persistency(all_packages, skip_ids_persistency)
|
@@ -801,7 +898,9 @@ module Aspera
|
|
801
898
|
when :tier_restrictions
|
802
899
|
return Main.result_single_object(aoc_api.read('tier_restrictions'))
|
803
900
|
when :user
|
804
|
-
case options.get_next_command(%i[workspaces profile preferences])
|
901
|
+
case options.get_next_command(%i[workspaces profile preferences contacts])
|
902
|
+
when :contacts
|
903
|
+
return execute_resource_action(:contact)
|
805
904
|
# when :settings
|
806
905
|
# return Main.result_object_list(aoc_api.read('client_settings/'))
|
807
906
|
when :workspaces
|
@@ -831,7 +930,7 @@ module Aspera
|
|
831
930
|
end
|
832
931
|
end
|
833
932
|
when :packages
|
834
|
-
package_command = options.get_next_command(%i[shared_inboxes send receive list show delete].concat(Node::NODE4_READ_ACTIONS), aliases: {recv: :receive})
|
933
|
+
package_command = options.get_next_command(%i[shared_inboxes send receive list show delete modify].concat(Node::NODE4_READ_ACTIONS), aliases: {recv: :receive})
|
835
934
|
case package_command
|
836
935
|
when :shared_inboxes
|
837
936
|
case options.get_next_command(%i[list show short_link])
|
@@ -853,7 +952,7 @@ module Aspera
|
|
853
952
|
package_data = value_create_modify(command: package_command)
|
854
953
|
new_user_option = options.get_option(:new_user_option)
|
855
954
|
option_validate = options.get_option(:validate_metadata)
|
856
|
-
#
|
955
|
+
# Works for both normal user auth and link auth.
|
857
956
|
workspace_id_hash(hash: package_data, string: true) unless package_data.key?('workspace_id')
|
858
957
|
if !aoc_api.public_link.nil?
|
859
958
|
aoc_api.assert_public_link_types(%w[send_package_to_user send_package_to_dropbox])
|
@@ -862,7 +961,7 @@ module Aspera
|
|
862
961
|
# enforce workspace id from link (should be already ok, but in case user wanted to override)
|
863
962
|
package_data['workspace_id'] = aoc_api.public_link['data']['workspace_id']
|
864
963
|
end
|
865
|
-
|
964
|
+
package_data['encryption_at_rest'] = true if transfer.option_transfer_spec['content_protection'].eql?('encrypt')
|
866
965
|
# transfer may raise an error
|
867
966
|
created_package = aoc_api.create_package_simple(package_data, option_validate, new_user_option)
|
868
967
|
Main.result_transfer(transfer.start(created_package[:spec], rest_token: created_package[:node]))
|
@@ -872,50 +971,70 @@ module Aspera
|
|
872
971
|
ids_to_download = nil
|
873
972
|
if !aoc_api.public_link.nil?
|
874
973
|
aoc_api.assert_public_link_types(['view_received_package'])
|
875
|
-
#
|
974
|
+
# Set the package id from link
|
876
975
|
ids_to_download = aoc_api.public_link['data']['package_id']
|
877
976
|
end
|
878
|
-
#
|
977
|
+
# Get from command line unless it was a public link
|
879
978
|
ids_to_download ||= instance_identifier
|
880
979
|
skip_ids_persistency = package_persistency
|
881
980
|
case ids_to_download
|
882
|
-
when SpecialValues::
|
981
|
+
when SpecialValues::INIT
|
982
|
+
all_packages = list_all_packages_with_query[:items]
|
983
|
+
Aspera.assert(skip_ids_persistency){'INIT requires option once_only'}
|
984
|
+
skip_ids_persistency.data.clear.concat(all_packages.map{ |e| e['id']})
|
985
|
+
skip_ids_persistency.save
|
986
|
+
return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
|
987
|
+
when SpecialValues::ALL
|
883
988
|
all_packages = list_all_packages_with_query[:items]
|
884
|
-
if ids_to_download.eql?(SpecialValues::INIT)
|
885
|
-
Aspera.assert(skip_ids_persistency){'INIT requires option once_only'}
|
886
|
-
skip_ids_persistency.data.clear.concat(all_packages.map{ |e| e['id']})
|
887
|
-
skip_ids_persistency.save
|
888
|
-
return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
|
889
|
-
end
|
890
989
|
# remove from list the ones already downloaded
|
891
990
|
reject_packages_from_persistency(all_packages, skip_ids_persistency)
|
892
991
|
ids_to_download = all_packages.map{ |e| e['id']}
|
992
|
+
formatter.display_status("Found #{ids_to_download.length} package(s).")
|
893
993
|
else
|
894
994
|
# single id to array
|
895
995
|
ids_to_download = [ids_to_download] unless ids_to_download.is_a?(Array)
|
896
996
|
end
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
997
|
+
# download all files, or specified list only
|
998
|
+
ts_paths = transfer.ts_source_paths(default: ['.'])
|
999
|
+
per_package_def = options.get_option(:package_folder)
|
1000
|
+
unless per_package_def.nil?
|
1001
|
+
raise Cli::BadArgument, "Invalid package folder option : #{per_package_def}" unless per_package_def =~ /\A([^+]+)(?:\+([^?]+)(\?)?)?\z/
|
1002
|
+
per_package_field1 = Regexp.last_match(1)
|
1003
|
+
per_package_field2 = Regexp.last_match(2)
|
1004
|
+
per_package_sub_always = Regexp.last_match(3).nil?
|
1005
|
+
end
|
1006
|
+
# get value outside of loop
|
1007
|
+
destination_folder = transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE)
|
904
1008
|
result_transfer = []
|
905
|
-
formatter.display_status("Found #{ids_to_download.length} package(s).")
|
906
1009
|
ids_to_download.each do |package_id|
|
907
1010
|
package_info = aoc_api.read("packages/#{package_id}")
|
908
|
-
formatter.display_status("downloading package: [#{package_info['id']}] #{package_info['name']}")
|
909
1011
|
package_node_api = aoc_api.node_api_from(
|
910
1012
|
node_id: package_info['node_id'],
|
911
1013
|
package_info: package_info,
|
912
|
-
**workspace_id_hash(name: true)
|
1014
|
+
**workspace_id_hash(name: true)
|
1015
|
+
)
|
1016
|
+
transfer_spec = package_node_api.transfer_spec_gen4(
|
1017
|
+
package_info['contents_file_id'],
|
1018
|
+
Transfer::Spec::DIRECTION_RECEIVE,
|
1019
|
+
{'paths'=> ts_paths}
|
1020
|
+
)
|
1021
|
+
unless per_package_def.nil?
|
1022
|
+
# folder based on first field
|
1023
|
+
folder = File.join(
|
1024
|
+
destination_folder,
|
1025
|
+
Environment.instance.sanitized_filename(package_info[per_package_field1])
|
1026
|
+
)
|
1027
|
+
transfer.option_transfer_spec['destination_root'] = self.class.unique_folder(
|
1028
|
+
folder,
|
1029
|
+
extension: per_package_field2.eql?('seq') ? :seq : package_info[per_package_field2],
|
1030
|
+
always: per_package_sub_always
|
1031
|
+
)
|
1032
|
+
end
|
1033
|
+
formatter.display_status(%Q{Downloading package: [#{package_info['id']}] "#{package_info['name']}" to [#{destination_folder}]})
|
913
1034
|
statuses = transfer.start(
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
{'paths'=> file_list}),
|
918
|
-
rest_token: package_node_api)
|
1035
|
+
transfer_spec,
|
1036
|
+
rest_token: package_node_api
|
1037
|
+
)
|
919
1038
|
result_transfer.push({'package' => package_id, Main::STATUS_FIELD => statuses})
|
920
1039
|
# update skip list only if all transfer sessions completed
|
921
1040
|
if skip_ids_persistency && TransferAgent.session_status(statuses).eql?(:success)
|
@@ -936,10 +1055,15 @@ module Aspera
|
|
936
1055
|
display_fields += ['workspace_id'] if aoc_api.workspace[:id].nil?
|
937
1056
|
return Main.result_object_list(result[:items], fields: display_fields, total: result[:total])
|
938
1057
|
when :delete
|
939
|
-
return do_bulk_operation(command: package_command,
|
1058
|
+
return do_bulk_operation(command: package_command, values: instance_identifier) do |id|
|
940
1059
|
Aspera.assert_values(id.class, [String, Integer]){'identifier'}
|
941
1060
|
aoc_api.delete("packages/#{id}")
|
942
1061
|
end
|
1062
|
+
when :modify
|
1063
|
+
id = instance_identifier
|
1064
|
+
package_data = value_create_modify(command: package_command)
|
1065
|
+
aoc_api.update("packages/#{id}", package_data)
|
1066
|
+
return Main.result_status('modified')
|
943
1067
|
when *Node::NODE4_READ_ACTIONS
|
944
1068
|
package_id = instance_identifier
|
945
1069
|
package_info = aoc_api.read("packages/#{package_id}")
|
@@ -954,7 +1078,8 @@ module Aspera
|
|
954
1078
|
folder_dest = options.get_next_argument('path', validation: String)
|
955
1079
|
home_node_api = aoc_api.node_api_from(
|
956
1080
|
node_id: aoc_api.home[:node_id],
|
957
|
-
**workspace_id_hash(name: true)
|
1081
|
+
**workspace_id_hash(name: true)
|
1082
|
+
)
|
958
1083
|
shared_apfid = home_node_api.resolve_api_fid(aoc_api.home[:file_id], folder_dest)
|
959
1084
|
return short_link_command(
|
960
1085
|
purpose_public: 'view_shared_file',
|
@@ -992,12 +1117,16 @@ module Aspera
|
|
992
1117
|
command_automation = options.get_next_command(%i[workflows instances])
|
993
1118
|
case command_automation
|
994
1119
|
when :instances
|
995
|
-
return
|
1120
|
+
return entity_execute(api: aoc_api, entity: 'workflow_instances')
|
996
1121
|
when :workflows
|
997
1122
|
wf_command = options.get_next_command(%i[action launch].concat(Plugin::ALL_OPS))
|
998
1123
|
case wf_command
|
999
1124
|
when *Plugin::ALL_OPS
|
1000
|
-
return
|
1125
|
+
return entity_execute(
|
1126
|
+
api: automation_api,
|
1127
|
+
entity: 'workflows',
|
1128
|
+
command: wf_command
|
1129
|
+
)
|
1001
1130
|
when :launch
|
1002
1131
|
wf_id = instance_identifier
|
1003
1132
|
data = automation_api.create("workflows/#{wf_id}/launch", {})
|