aspera-cli 4.27.0 → 4.27.1
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 +29 -0
- data/CONTRIBUTING.md +1 -7
- data/TODO.md +50 -0
- data/docs/README.md +708 -488
- data/lib/aspera/agent/base.rb +10 -2
- data/lib/aspera/agent/connect.rb +7 -7
- data/lib/aspera/agent/desktop.rb +3 -3
- data/lib/aspera/agent/direct.rb +48 -19
- data/lib/aspera/agent/factory.rb +3 -3
- data/lib/aspera/agent/httpgw.rb +55 -14
- data/lib/aspera/agent/node.rb +2 -2
- data/lib/aspera/agent/transferd.rb +12 -12
- data/lib/aspera/api/aoc.rb +28 -28
- data/lib/aspera/api/cos_node.rb +10 -9
- data/lib/aspera/api/faspex.rb +2 -2
- data/lib/aspera/api/httpgw.rb +20 -20
- data/lib/aspera/api/node.rb +31 -53
- data/lib/aspera/ascmd.rb +13 -13
- data/lib/aspera/ascp/installation.rb +43 -36
- data/lib/aspera/ascp/management.rb +6 -6
- data/lib/aspera/assert.rb +12 -13
- data/lib/aspera/cli/ascp_actions.rb +7 -7
- data/lib/aspera/cli/async_transfer_store.rb +49 -5
- data/lib/aspera/cli/bootstrapper.rb +9 -9
- data/lib/aspera/cli/command_registry.rb +1 -1
- data/lib/aspera/cli/command_spec.rb +6 -3
- data/lib/aspera/cli/context.rb +3 -3
- data/lib/aspera/cli/extended_value.rb +26 -26
- data/lib/aspera/cli/formatter.rb +76 -54
- data/lib/aspera/cli/gem_checker.rb +1 -1
- data/lib/aspera/cli/hints.rb +2 -2
- data/lib/aspera/cli/http.rb +22 -29
- data/lib/aspera/cli/mailer.rb +7 -7
- data/lib/aspera/cli/mcp_tool.rb +31 -4
- data/lib/aspera/cli/option_declarator.rb +77 -0
- data/lib/aspera/cli/options.schema.yaml +273 -3
- data/lib/aspera/cli/parser.rb +539 -280
- data/lib/aspera/cli/plugins/alee.rb +1 -1
- data/lib/aspera/cli/plugins/aoc.rb +297 -313
- data/lib/aspera/cli/plugins/ats.rb +25 -21
- data/lib/aspera/cli/plugins/base.rb +357 -186
- data/lib/aspera/cli/plugins/basic_auth.rb +0 -12
- data/lib/aspera/cli/plugins/config.rb +76 -73
- data/lib/aspera/cli/plugins/console.rb +8 -8
- data/lib/aspera/cli/plugins/cos.rb +4 -3
- data/lib/aspera/cli/plugins/factory.rb +2 -2
- data/lib/aspera/cli/plugins/faspex5.rb +259 -248
- data/lib/aspera/cli/plugins/faspio.rb +7 -2
- data/lib/aspera/cli/plugins/httpgw.rb +1 -1
- data/lib/aspera/cli/plugins/mcp.rb +11 -11
- data/lib/aspera/cli/plugins/node.rb +227 -283
- data/lib/aspera/cli/plugins/orchestrator.rb +23 -23
- data/lib/aspera/cli/plugins/preview.rb +61 -64
- data/lib/aspera/cli/plugins/server.rb +36 -31
- data/lib/aspera/cli/plugins/shares.rb +174 -135
- data/lib/aspera/cli/preset_actions.rb +39 -19
- data/lib/aspera/cli/preset_manager.rb +74 -32
- data/lib/aspera/cli/result.rb +18 -16
- data/lib/aspera/cli/runner.rb +75 -39
- data/lib/aspera/cli/secret_finder.rb +1 -1
- data/lib/aspera/cli/sync_actions.rb +36 -35
- data/lib/aspera/cli/terminal_formatter.rb +2 -2
- data/lib/aspera/cli/transfer_actions.rb +17 -10
- data/lib/aspera/cli/transfer_agent.rb +44 -44
- data/lib/aspera/cli/transfer_progress.rb +7 -7
- data/lib/aspera/cli/vault_manager.rb +34 -12
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +17 -20
- data/lib/aspera/colors.rb +3 -3
- data/lib/aspera/command_line_builder.rb +16 -16
- data/lib/aspera/command_line_converter.rb +1 -1
- data/lib/aspera/coverage.rb +1 -2
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/dot_container.rb +8 -8
- data/lib/aspera/environment.rb +12 -12
- data/lib/aspera/faspex_gw.rb +4 -4
- data/lib/aspera/faspex_postproc.rb +14 -9
- data/lib/aspera/graphql.rb +4 -2
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/json_rpc/client.rb +1 -1
- data/lib/aspera/keychain/base.rb +10 -3
- data/lib/aspera/keychain/encrypted_hash.rb +92 -17
- data/lib/aspera/keychain/factory.rb +17 -5
- data/lib/aspera/keychain/hashicorp_vault.rb +1 -1
- data/lib/aspera/keychain/macos_security.rb +23 -25
- data/lib/aspera/keychain/one_password_api.rb +86 -0
- data/lib/aspera/keychain/one_password_base.rb +34 -0
- data/lib/aspera/keychain/one_password_cli.rb +98 -0
- data/lib/aspera/link_header.rb +2 -2
- data/lib/aspera/log.rb +13 -13
- data/lib/aspera/markdown.rb +5 -5
- data/lib/aspera/nagios.rb +8 -8
- data/lib/aspera/node_simulator.rb +33 -27
- data/lib/aspera/oauth/base.rb +4 -5
- data/lib/aspera/oauth/boot.rb +3 -3
- data/lib/aspera/oauth/factory.rb +5 -5
- data/lib/aspera/oauth/jwt.rb +5 -7
- data/lib/aspera/oauth/web.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +8 -8
- data/lib/aspera/preview/file_types.rb +4 -4
- data/lib/aspera/preview/generator.rb +49 -46
- data/lib/aspera/preview/options.rb +3 -2
- data/lib/aspera/preview/terminal.rb +5 -5
- data/lib/aspera/preview/utils.rb +65 -18
- data/lib/aspera/products/connect.rb +2 -2
- data/lib/aspera/products/desktop.rb +1 -1
- data/lib/aspera/products/other.rb +2 -2
- data/lib/aspera/products/transferd.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +10 -10
- data/lib/aspera/rest.rb +149 -115
- data/lib/aspera/rest_error_analyzer.rb +3 -3
- data/lib/aspera/rest_list.rb +10 -9
- data/lib/aspera/schema/IBM Aspera Node API-4.4.6.yaml +6232 -0
- data/lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml +249 -0
- data/lib/aspera/schema/IBM_Aspera_Shares.yaml +4653 -0
- data/lib/aspera/schema/documentation.rb +17 -11
- data/lib/aspera/schema/reader.rb +78 -4
- data/lib/aspera/schema/registry.rb +26 -7
- data/lib/aspera/secret_hider.rb +5 -5
- data/lib/aspera/ssh.rb +64 -31
- data/lib/aspera/ssl.rb +3 -3
- data/lib/aspera/sync/database.rb +2 -2
- data/lib/aspera/sync/operations.rb +13 -13
- data/lib/aspera/temp_file_manager.rb +24 -4
- data/lib/aspera/transfer/faux_file.rb +2 -2
- data/lib/aspera/transfer/parameters.rb +15 -15
- data/lib/aspera/transfer/resumer.rb +9 -9
- data/lib/aspera/transfer/spec.rb +1 -1
- data/lib/aspera/uri_reader.rb +52 -15
- data/lib/aspera/web_auth.rb +6 -5
- data/lib/aspera/web_server_simple.rb +9 -9
- data/lib/aspera/yaml.rb +4 -4
- data.tar.gz.sig +0 -0
- metadata +10 -4
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/plugins/faspex.rb +0 -576
- data/lib/aspera/transfer/uri.rb +0 -56
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# spellchecker: ignore workgroups mypackages passcode
|
|
4
4
|
|
|
5
|
+
require 'aspera/schema/registry'
|
|
5
6
|
require 'aspera/cli/plugins/oauth'
|
|
6
7
|
require 'aspera/cli/extended_value'
|
|
7
8
|
require 'aspera/transfer/result'
|
|
@@ -46,7 +47,7 @@ module Aspera
|
|
|
46
47
|
}
|
|
47
48
|
rescue StandardError => e
|
|
48
49
|
error = e
|
|
49
|
-
Log.log.debug{"detect error: #{e}"}
|
|
50
|
+
Log.log.debug { "detect error: #{e}" }
|
|
50
51
|
end
|
|
51
52
|
raise error if error
|
|
52
53
|
return
|
|
@@ -80,14 +81,12 @@ module Aspera
|
|
|
80
81
|
)
|
|
81
82
|
return {
|
|
82
83
|
preset_value: {
|
|
83
|
-
url:
|
|
84
|
-
username:
|
|
85
|
-
auth:
|
|
86
|
-
private_key:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
client_secret: client_secret
|
|
90
|
-
}
|
|
84
|
+
url: app_url,
|
|
85
|
+
username: wiz_username,
|
|
86
|
+
auth: :jwt.to_s,
|
|
87
|
+
private_key: "@file:#{private_key_path}",
|
|
88
|
+
client_id: client_id,
|
|
89
|
+
client_secret: client_secret
|
|
91
90
|
},
|
|
92
91
|
test_args: 'user profile show'
|
|
93
92
|
}
|
|
@@ -108,7 +107,7 @@ module Aspera
|
|
|
108
107
|
def normalize_recipients(parameters, type)
|
|
109
108
|
type = type.to_s
|
|
110
109
|
return unless parameters.key?(type)
|
|
111
|
-
Aspera.assert_type(parameters[type], Array){type}
|
|
110
|
+
Aspera.assert_type(parameters[type], Array) { type }
|
|
112
111
|
recipient_types = Api::Faspex::RECIPIENT_TYPES
|
|
113
112
|
if parameters.key?('recipient_types')
|
|
114
113
|
recipient_types = parameters['recipient_types']
|
|
@@ -169,9 +168,15 @@ module Aspera
|
|
|
169
168
|
return result
|
|
170
169
|
end
|
|
171
170
|
|
|
172
|
-
#
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
# List all packages with optional filter.
|
|
172
|
+
# The special `max` key is extracted *before* the API call and returned separately,
|
|
173
|
+
# so callers that apply a post-API filter (e.g. once_only) can enforce the limit
|
|
174
|
+
# after filtering rather than before.
|
|
175
|
+
# @param filter [Proc, nil] optional filter lambda applied to each package entry
|
|
176
|
+
# @param query [Hash] additional query parameters forwarded to the API
|
|
177
|
+
# @return [Array(Array, Integer|nil, Integer|nil)] [filtered list, max (or nil), total count]
|
|
178
|
+
def list_packages_with_filter(filter: nil, query: {})
|
|
179
|
+
filter ||= ->(_x) { true }
|
|
175
180
|
box = options.get_option(:box)
|
|
176
181
|
# Translate box name to API prefix (with ending slash)
|
|
177
182
|
entity =
|
|
@@ -182,8 +187,13 @@ module Aspera
|
|
|
182
187
|
group_type = options.get_option(:group_type)
|
|
183
188
|
"#{group_type}/#{@api_v5.lookup_entity_by_field(entity: group_type, value: box)['id']}/packages"
|
|
184
189
|
end
|
|
185
|
-
|
|
186
|
-
|
|
190
|
+
# Merge default query with user-provided query: user values take precedence, but defaults are preserved
|
|
191
|
+
user_query = query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::FASPEX, 'packages'))
|
|
192
|
+
merged_query = user_query.nil? ? query.dup : query.merge(user_query)
|
|
193
|
+
# Extract `max` before the API call so callers can apply it after post-API filtering
|
|
194
|
+
max_items = merged_query.delete(RestList::MAX_ITEMS)&.to_i
|
|
195
|
+
list, total = @api_v5.list_entities_limit_offset_total_count(entity: entity, query: merged_query)
|
|
196
|
+
return list.select(&filter), max_items, total
|
|
187
197
|
end
|
|
188
198
|
|
|
189
199
|
# Build query to get package recipients based on package info in case of shared inbox or workgroup recipient
|
|
@@ -216,22 +226,24 @@ module Aspera
|
|
|
216
226
|
case package_ids
|
|
217
227
|
when SpecialValues::INIT
|
|
218
228
|
Aspera.assert(skip_ids_persistency, 'Only with option once_only')
|
|
219
|
-
skip_ids_persistency.data.clear.concat(list_packages_with_filter.first.map{ |p| p['id']})
|
|
229
|
+
skip_ids_persistency.data.clear.concat(list_packages_with_filter.first.map { |p| p['id'] }) # no filter: all packages, max ignored
|
|
220
230
|
skip_ids_persistency.save
|
|
221
231
|
return Result::Status.new("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
|
|
222
232
|
when SpecialValues::ALL
|
|
223
233
|
# TODO: if packages have same name, they will overwrite ?
|
|
224
|
-
packages = list_packages_with_filter(query: {'status' => 'completed'})
|
|
225
|
-
Log.dump(:package_ids, level: :trace1){packages.map{ |p| p['id']}}
|
|
234
|
+
packages, max_items = list_packages_with_filter(query: {'status' => 'completed'}) # no filter: all completed packages
|
|
235
|
+
Log.dump(:package_ids, level: :trace1) { packages.map { |p| p['id'] } }
|
|
226
236
|
Log.dump(:skip_ids, skip_ids_persistency.data, level: :trace1)
|
|
227
|
-
packages.reject!{ |p| skip_ids_persistency.data.include?(p['id'])} if skip_ids_persistency
|
|
228
|
-
|
|
237
|
+
packages.reject! { |p| skip_ids_persistency.data.include?(p['id']) } if skip_ids_persistency
|
|
238
|
+
# Apply `max` after once_only filtering so we get the N first not-yet-downloaded packages
|
|
239
|
+
packages = packages[0, max_items] if max_items
|
|
240
|
+
Log.dump(:package_ids, level: :trace1) { packages.map { |p| p['id'] } }
|
|
229
241
|
else
|
|
230
242
|
# a single id was provided, or a list of ids
|
|
231
243
|
package_ids = [package_ids] unless package_ids.is_a?(Array)
|
|
232
|
-
Aspera.assert_array_all(package_ids, String){'Package id(s)'}
|
|
244
|
+
Aspera.assert_array_all(package_ids, String) { 'Package id(s)' }
|
|
233
245
|
# packages = package_ids.map{|pkg_id|@api_v5.read("packages/#{pkg_id}")}
|
|
234
|
-
packages = package_ids.map{ |pkg_id| {'id'=>pkg_id}}
|
|
246
|
+
packages = package_ids.map { |pkg_id| {'id'=>pkg_id} }
|
|
235
247
|
end
|
|
236
248
|
result_transfer = []
|
|
237
249
|
param_file_list = {}
|
|
@@ -279,7 +291,7 @@ module Aspera
|
|
|
279
291
|
recipient_type: @api_v5.pub_link_context['recipient_type']
|
|
280
292
|
}]
|
|
281
293
|
end
|
|
282
|
-
PACKAGE_RECIPIENT_TYPES.each{ |type| normalize_recipients(parameters, type)}
|
|
294
|
+
PACKAGE_RECIPIENT_TYPES.each { |type| normalize_recipients(parameters, type) }
|
|
283
295
|
# User specified content prot in tspec, but faspex requires in package creation
|
|
284
296
|
# `transfer_spec/upload` will set `content_protection`
|
|
285
297
|
if transfer.user_transfer_spec['content_protection'] && !parameters.key?('ear_enabled')
|
|
@@ -325,13 +337,13 @@ module Aspera
|
|
|
325
337
|
def browse_folder(browse_endpoint, base_query = {}, folder_path: '/')
|
|
326
338
|
folders_to_process = [folder_path]
|
|
327
339
|
query = base_query.merge(query_read_delete(default: {}))
|
|
328
|
-
filters = query.delete('filters'){{}}
|
|
340
|
+
filters = query.delete('filters') { {} }
|
|
329
341
|
Aspera.assert_type(filters, Hash)
|
|
330
342
|
filters['basenames'] ||= []
|
|
331
|
-
Aspera.assert_type(filters, Hash){'filters'}
|
|
343
|
+
Aspera.assert_type(filters, Hash) { 'filters' }
|
|
332
344
|
max_items = query.delete(RestList::MAX_ITEMS)
|
|
333
345
|
recursive = query.delete('recursive')
|
|
334
|
-
use_paging = query.delete('paging'){true}
|
|
346
|
+
use_paging = query.delete('paging') { true }
|
|
335
347
|
if use_paging
|
|
336
348
|
browse_endpoint = "#{browse_endpoint}/page"
|
|
337
349
|
query['per_page'] ||= 500
|
|
@@ -358,7 +370,7 @@ module Aspera
|
|
|
358
370
|
all_items = all_items.slice(0, max_items) if all_items.count > max_items
|
|
359
371
|
break
|
|
360
372
|
end
|
|
361
|
-
folders_to_process.concat(data['items'].select{ |i| i['type'].eql?('directory')}.map{ |i| i['path']}) if recursive
|
|
373
|
+
folders_to_process.concat(data['items'].select { |i| i['type'].eql?('directory') }.map { |i| i['path'] }) if recursive
|
|
362
374
|
if use_paging
|
|
363
375
|
iteration_token = http[Api::Faspex::HEADER_X_NEXT_ITER_TOKEN]
|
|
364
376
|
break if iteration_token.nil? || iteration_token.empty?
|
|
@@ -377,26 +389,27 @@ module Aspera
|
|
|
377
389
|
end
|
|
378
390
|
|
|
379
391
|
# Per-resource configuration for admin CRUD sub-trees.
|
|
380
|
-
# Keys mirror
|
|
392
|
+
# Keys mirror entity_list/show/create/modify/delete kwargs; extra_commands lists additional leaf commands.
|
|
381
393
|
# @return [Hash{Symbol => Hash}]
|
|
382
394
|
RESOURCE_CONFIG = {
|
|
383
395
|
accounts: {
|
|
384
|
-
display_fields: ->{Formatter.all_but('user_profile_data_attributes')},
|
|
396
|
+
display_fields: -> { Formatter.all_but('user_profile_data_attributes') },
|
|
385
397
|
extra_commands: [:reset_password],
|
|
386
|
-
instance_arg_commands: {reset_password: {arguments: [{name: :contact_id, type: :identifier, lookup: :
|
|
387
|
-
query_component: Schema::Registry::FASPEX
|
|
398
|
+
instance_arg_commands: {reset_password: {arguments: [{name: :contact_id, type: :identifier, lookup: ->(field, value, **) { res_lookup_id(:accounts, field, value) }}]}},
|
|
399
|
+
query_component: Schema::Registry::FASPEX,
|
|
400
|
+
body_component: Schema::Registry::FASPEX
|
|
388
401
|
},
|
|
389
|
-
alternate_addresses: {entity: 'configuration/alternate_addresses', query_component: Schema::Registry::FASPEX},
|
|
402
|
+
alternate_addresses: {entity: 'configuration/alternate_addresses', query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
390
403
|
contacts: {query_component: Schema::Registry::FASPEX},
|
|
391
|
-
distribution_lists: {entity: 'account/distribution_lists', delete_style: 'ids', query_component: Schema::Registry::FASPEX},
|
|
404
|
+
distribution_lists: {entity: 'account/distribution_lists', delete_style: 'ids', query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
392
405
|
email_notifications: {id_as_arg: 'type', query_component: Schema::Registry::FASPEX},
|
|
393
406
|
file_processing: {
|
|
394
|
-
commands:
|
|
395
|
-
|
|
396
|
-
is_singleton:
|
|
407
|
+
commands: %i[next modify],
|
|
408
|
+
body_component: Schema::Registry::FASPEX,
|
|
409
|
+
is_singleton: true
|
|
397
410
|
},
|
|
398
411
|
jobs: {display_fields: %w[id job_name job_type status], query_component: Schema::Registry::FASPEX},
|
|
399
|
-
metadata_profiles: {entity: 'configuration/metadata_profiles', items_key: 'profiles', query_component: Schema::Registry::FASPEX},
|
|
412
|
+
metadata_profiles: {entity: 'configuration/metadata_profiles', items_key: 'profiles', query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
400
413
|
nodes: {
|
|
401
414
|
extra_commands: %i[browse],
|
|
402
415
|
instance_arg_commands: {
|
|
@@ -405,19 +418,21 @@ module Aspera
|
|
|
405
418
|
{name: :folder_path, type: String, mandatory: false, default: '/'}]
|
|
406
419
|
}
|
|
407
420
|
},
|
|
408
|
-
query_component: Schema::Registry::FASPEX
|
|
421
|
+
query_component: Schema::Registry::FASPEX,
|
|
422
|
+
body_component: Schema::Registry::FASPEX
|
|
409
423
|
},
|
|
410
424
|
oauth_clients: {
|
|
411
|
-
display_fields: ->{Formatter.all_but('public_key')},
|
|
412
|
-
api: ->{Api::Faspex.new(root: Api::Faspex::PATH_AUTH, **Oauth.kwargs_from_options(options))},
|
|
425
|
+
display_fields: -> { Formatter.all_but('public_key') },
|
|
426
|
+
api: -> { Api::Faspex.new(root: Api::Faspex::PATH_AUTH, **Oauth.kwargs_from_options(options)) },
|
|
413
427
|
list_query: {'expand': true, 'no_api_path': true, 'client_types[]': 'public'},
|
|
414
|
-
query_component: Schema::Registry::FASPEX
|
|
428
|
+
query_component: Schema::Registry::FASPEX,
|
|
429
|
+
body_component: Schema::Registry::FASPEX
|
|
415
430
|
},
|
|
416
431
|
registrations: {query_component: Schema::Registry::FASPEX},
|
|
417
|
-
saml_configs: {query_component: Schema::Registry::FASPEX},
|
|
418
|
-
shared_inboxes: {res_id_query: {'all': true}, query_component: Schema::Registry::FASPEX},
|
|
419
|
-
webhooks: {query_component: Schema::Registry::FASPEX},
|
|
420
|
-
workgroups: {res_id_query: {'all': true}, query_component: Schema::Registry::FASPEX}
|
|
432
|
+
saml_configs: {query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
433
|
+
shared_inboxes: {res_id_query: {'all': true}, query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
434
|
+
webhooks: {query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
435
|
+
workgroups: {res_id_query: {'all': true}, query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX}
|
|
421
436
|
}.freeze
|
|
422
437
|
private_constant :RESOURCE_CONFIG
|
|
423
438
|
|
|
@@ -427,7 +442,7 @@ module Aspera
|
|
|
427
442
|
v.is_a?(Proc) ? instance_exec(&v) : v
|
|
428
443
|
end
|
|
429
444
|
|
|
430
|
-
# Build
|
|
445
|
+
# Build args hash from RESOURCE_CONFIG for use with entity_list/show/create/modify/delete.
|
|
431
446
|
def res_exec_args(res_sym)
|
|
432
447
|
cfg = RESOURCE_CONFIG.fetch(res_sym, {})
|
|
433
448
|
{
|
|
@@ -439,33 +454,16 @@ module Aspera
|
|
|
439
454
|
display_fields: resource_config_value(cfg, :display_fields),
|
|
440
455
|
list_query: resource_config_value(cfg, :list_query),
|
|
441
456
|
is_singleton: resource_config_value(cfg, :is_singleton) || false,
|
|
442
|
-
|
|
443
|
-
|
|
457
|
+
query_component: resource_config_value(cfg, :query_component),
|
|
458
|
+
body_component: resource_config_value(cfg, :body_component)
|
|
444
459
|
}.compact
|
|
445
460
|
end
|
|
446
461
|
|
|
447
|
-
# Lookup methods for arguments: + lookup: on specific nodes
|
|
448
|
-
|
|
449
462
|
# admin > nodes — lookup node id by field/value
|
|
450
463
|
def lookup_node_id(field, value, **)
|
|
451
464
|
@api_v5.lookup_entity_by_field(entity: 'nodes', field: field, value: value)['id']
|
|
452
465
|
end
|
|
453
466
|
|
|
454
|
-
# admin > shared_inboxes — lookup id by field/value
|
|
455
|
-
def lookup_shared_inboxes_id(field, value, **)
|
|
456
|
-
@api_v5.lookup_entity_by_field(entity: 'shared_inboxes', field: field, value: value, query: {'all': true})['id']
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
# admin > workgroups — lookup id by field/value
|
|
460
|
-
def lookup_workgroups_id(field, value, **)
|
|
461
|
-
@api_v5.lookup_entity_by_field(entity: 'workgroups', field: field, value: value, query: {'all': true})['id']
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
# admin > accounts — lookup id by field/value (used for reset_password arguments:)
|
|
465
|
-
def lookup_accounts_id(field, value, **)
|
|
466
|
-
res_lookup_id(:accounts, field, value)
|
|
467
|
-
end
|
|
468
|
-
|
|
469
467
|
# Lookup id for a RESOURCE_CONFIG resource by field/value.
|
|
470
468
|
def res_lookup_id(res_sym, field, value)
|
|
471
469
|
cfg = RESOURCE_CONFIG.fetch(res_sym, {})
|
|
@@ -475,32 +473,38 @@ module Aspera
|
|
|
475
473
|
@api_v5.lookup_entity_by_field(entity: entity, value: value, field: field, items_key: items_key, query: res_id_query)['id']
|
|
476
474
|
end
|
|
477
475
|
|
|
476
|
+
# Dynamically define lookup methods for admin resources (used by crud_commands)
|
|
477
|
+
Api::Faspex::ADMIN_RESOURCES.each do |res|
|
|
478
|
+
define_method(:"lookup_admin_#{res}_id") do |field, value, **|
|
|
479
|
+
res_lookup_id(res, field, value)
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
|
|
478
483
|
# --- DSL ---
|
|
479
484
|
|
|
480
485
|
# Commands that need @api_v5 carry setup: :setup_api_v5.
|
|
481
486
|
# :health and :postprocessing work without authentication, so they have no setup.
|
|
482
487
|
command :health, description: 'Check Faspex 5 health'
|
|
483
|
-
command :version, description: 'Show Faspex 5 version', setup: :setup_api_v5, action: ->{Result::SingleObject.new(@api_v5.read('version'))}
|
|
484
|
-
command :bearer_token, description: 'Show OAuth bearer token', setup: :setup_api_v5, action: ->{Result::Text.new(@api_v5.oauth.authorization)}
|
|
488
|
+
command :version, description: 'Show Faspex 5 version', setup: :setup_api_v5, action: -> { Result::SingleObject.new(@api_v5.read('version')) }
|
|
489
|
+
command :bearer_token, description: 'Show OAuth bearer token', setup: :setup_api_v5, action: -> { Result::Text.new(@api_v5.oauth.authorization) }
|
|
485
490
|
command :packages, description: 'Manage packages', setup: :setup_api_v5
|
|
486
|
-
commands_under
|
|
487
|
-
command :list, description: 'List packages'
|
|
491
|
+
commands_under :packages do
|
|
492
|
+
command :list, description: 'List packages',
|
|
493
|
+
arguments: [{name: :filter, mandatory: false, default: nil, type: Proc}]
|
|
488
494
|
command :send, description: 'Send a package', transfer_paths: :send,
|
|
489
495
|
arguments: [{name: :data, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::FASPEX, 'packages.post')}],
|
|
490
|
-
action: ->(data:, **){package_send(data)}
|
|
496
|
+
action: ->(data:, **) { package_send(data) }
|
|
491
497
|
command :show, description: 'Show a package', setup: :setup_package_id,
|
|
492
|
-
action: ->(package_id:, **){Result::SingleObject.new(@api_v5.read("packages/#{package_id}"))}
|
|
498
|
+
action: ->(package_id:, **) { Result::SingleObject.new(@api_v5.read("packages/#{package_id}")) }
|
|
493
499
|
command :browse, description: 'Browse package files', setup: :setup_package_id,
|
|
494
500
|
arguments: [{name: :folder_path, type: String, mandatory: false, default: '/'}],
|
|
495
|
-
action: ->(folder_path:, package_id:, **){browse_folder("packages/#{package_id}/files/#{Api::Faspex.box_type(options.get_option(:box))}", recipient_query(package_id), folder_path: folder_path)}
|
|
496
|
-
command
|
|
497
|
-
:status, description: 'Wait for package status', setup: :setup_package_id,
|
|
501
|
+
action: ->(folder_path:, package_id:, **) { browse_folder("packages/#{package_id}/files/#{Api::Faspex.box_type(options.get_option(:box))}", recipient_query(package_id), folder_path: folder_path) }
|
|
502
|
+
command :status, description: 'Wait for package status', setup: :setup_package_id,
|
|
498
503
|
arguments: [{name: :status_list, type: Array, mandatory: false, default: nil}],
|
|
499
|
-
action: ->(status_list:, package_id:, **){Result::SingleObject.new(wait_package_status(package_id, status_list: status_list))}
|
|
500
|
-
|
|
501
|
-
command :delete, description: 'Delete package(s)', setup: :setup_package_id
|
|
504
|
+
action: ->(status_list:, package_id:, **) { Result::SingleObject.new(wait_package_status(package_id, status_list: status_list)) }
|
|
505
|
+
command :delete, description: 'Delete packages', setup: :setup_package_id
|
|
502
506
|
command :receive, description: 'Receive a package', setup: :setup_package_id, transfer_paths: :receive,
|
|
503
|
-
action: ->(package_id:, **){package_receive(package_id)}
|
|
507
|
+
action: ->(package_id:, **) { package_receive(package_id) }
|
|
504
508
|
command(:file_processing, description: 'Show file processing status', setup: :setup_package_id, action: lambda do |package_id:, **|
|
|
505
509
|
result, count = @api_v5.list_entities_limit_offset_total_count(entity: "packages/#{package_id}/file_statuses", items_key: 'files')
|
|
506
510
|
Result::ObjectList.new(result, total: count)
|
|
@@ -515,25 +519,28 @@ module Aspera
|
|
|
515
519
|
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}}]
|
|
516
520
|
command :invitations, description: 'Manage invitations', setup: :setup_api_v5
|
|
517
521
|
|
|
518
|
-
commands_under
|
|
522
|
+
commands_under :invitations do
|
|
519
523
|
command :create, description: 'Create an invitation',
|
|
520
524
|
arguments: [{name: :input_data, type: Hash, bulk: true}]
|
|
521
525
|
command :resend, description: 'Resend an invitation',
|
|
522
526
|
arguments: [{name: :invitation_id, type: :identifier}]
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
527
|
+
crud_commands entity: 'invitations',
|
|
528
|
+
api: :@api_v5,
|
|
529
|
+
operations: Operations::ALL - %i[create],
|
|
530
|
+
items_key: 'invitations',
|
|
531
|
+
display_fields: %w[id public recipient_type recipient_name email_address]
|
|
526
532
|
end
|
|
527
533
|
|
|
528
|
-
commands_under
|
|
529
|
-
command :account, description: 'Show account information', action: ->{Result::SingleObject.new(@api_v5.read('account', query_read_delete))}
|
|
534
|
+
commands_under :user do
|
|
535
|
+
command :account, description: 'Show account information', action: -> { Result::SingleObject.new(@api_v5.read('account', query_read_delete)) }
|
|
530
536
|
command :profile, description: 'Manage user profile'
|
|
531
537
|
end
|
|
532
538
|
|
|
533
|
-
commands_under
|
|
534
|
-
command :show, description: 'Show user profile', action: ->{Result::SingleObject.new(@api_v5.read('account/preferences'))}
|
|
539
|
+
commands_under %i[user profile] do
|
|
540
|
+
command :show, description: 'Show user profile', action: -> { Result::SingleObject.new(@api_v5.read('account/preferences')) }
|
|
535
541
|
command(
|
|
536
|
-
:modify,
|
|
542
|
+
:modify,
|
|
543
|
+
description: 'Modify user profile',
|
|
537
544
|
arguments: [{name: :properties, type: Hash}],
|
|
538
545
|
action: lambda do |properties:, **|
|
|
539
546
|
@api_v5.update('account/preferences', properties)
|
|
@@ -542,15 +549,15 @@ module Aspera
|
|
|
542
549
|
)
|
|
543
550
|
end
|
|
544
551
|
|
|
545
|
-
commands_under
|
|
546
|
-
command :list, description: 'List shared folders', action: ->{Result::ObjectList.new(@api_v5.read('shared_folders')['shared_folders'])}
|
|
552
|
+
commands_under :shared_folders do
|
|
553
|
+
command :list, description: 'List shared folders', action: -> { Result::ObjectList.new(@api_v5.read('shared_folders')['shared_folders']) }
|
|
547
554
|
command :browse, description: 'Browse a shared folder',
|
|
548
555
|
arguments: [{name: :shared_folder_id, type: :identifier, lookup: :lookup_shared_folder_id},
|
|
549
556
|
{name: :folder_path, type: String, mandatory: false, default: '/'}]
|
|
550
557
|
end
|
|
551
558
|
|
|
552
559
|
# admin sub-tree: fixed commands + all ADMIN_RESOURCES with their sub-commands
|
|
553
|
-
commands_under
|
|
560
|
+
commands_under :admin do
|
|
554
561
|
command :configuration, description: 'Manage Faspex 5 configuration'
|
|
555
562
|
command :smtp, description: 'Manage SMTP configuration'
|
|
556
563
|
command :events, description: 'List events'
|
|
@@ -559,127 +566,155 @@ module Aspera
|
|
|
559
566
|
Api::Faspex::ADMIN_RESOURCES.each do |res|
|
|
560
567
|
cfg = RESOURCE_CONFIG.fetch(res, {})
|
|
561
568
|
extra = cfg[:extra_commands] || []
|
|
562
|
-
cmds = cfg[:commands] || (Operations::ALL + extra)
|
|
563
569
|
ia_cmds = cfg[:instance_arg_commands] || {}
|
|
564
570
|
is_singleton = cfg[:is_singleton] || false
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
571
|
+
entity_path = cfg[:entity] || res.to_s
|
|
572
|
+
crud_ops = ((cfg[:commands] || Operations::ALL) - %i[list]) & Operations::ALL
|
|
573
|
+
|
|
574
|
+
command res, description: "Manage #{res.to_s.tr('_', ' ')}"
|
|
575
|
+
commands_under(res) do
|
|
576
|
+
# List is handled with Faspex 5 pagination (item_list_with_total)
|
|
577
|
+
unless is_singleton
|
|
578
|
+
list_kwargs = {description: 'List'}
|
|
579
|
+
list_kwargs[:query_schema] = Schema::Registry.query_params(cfg[:query_component], entity_path) if cfg[:query_component]
|
|
580
|
+
command :list, **list_kwargs
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
# Standard CRUD operations handled via crud_commands
|
|
584
|
+
crud_commands(
|
|
585
|
+
api: -> { res_exec_args(res)[:api] },
|
|
586
|
+
entity: entity_path,
|
|
587
|
+
operations: crud_ops,
|
|
588
|
+
lookup: :"lookup_admin_#{res}_id",
|
|
589
|
+
is_singleton: is_singleton,
|
|
590
|
+
body_component: cfg[:body_component],
|
|
591
|
+
display_fields: cfg[:display_fields],
|
|
592
|
+
delete_style: cfg[:delete_style],
|
|
593
|
+
id_as_arg: cfg[:id_as_arg] || false
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
# Extra commands (e.g. browse, reset_password, next)
|
|
597
|
+
extra.each do |c|
|
|
569
598
|
ia = ia_cmds[c] || {}
|
|
570
|
-
|
|
571
|
-
if !is_singleton && c.eql?(:create)
|
|
572
|
-
[{name: :input_data, type: Hash, bulk: true, schema: schema_val}]
|
|
573
|
-
elsif c.eql?(:modify)
|
|
574
|
-
[{name: :input_data, type: Hash, schema: schema_val}]
|
|
575
|
-
else
|
|
576
|
-
[]
|
|
577
|
-
end
|
|
578
|
-
# Merge arguments: from ia (e.g. identifier spec) with extra_args for this operation
|
|
579
|
-
merged_args = Array(ia[:arguments]) + extra_args
|
|
580
|
-
spec_kwargs = merged_args.empty? ? ia.except(:arguments) : ia.except(:arguments).merge(arguments: merged_args)
|
|
581
|
-
# Attach query_schema (full path) to :list/:delete CommandSpec so --help shows the tip.
|
|
582
|
-
# cfg[:query_component] is always a String constant so direct read is safe here (no Proc).
|
|
583
|
-
if QUERY_SCHEMA_COMMANDS.include?(c) && cfg[:query_component]
|
|
584
|
-
entity_path = cfg[:entity] || res.to_s
|
|
585
|
-
spec_kwargs = spec_kwargs.merge(
|
|
586
|
-
query_schema: Schema::Registry.query_params(cfg[:query_component], entity_path)
|
|
587
|
-
)
|
|
588
|
-
end
|
|
589
|
-
command(c, description: c.to_s.tr('_', ' ').capitalize, **spec_kwargs)
|
|
599
|
+
command c, description: c.to_s.tr('_', ' ').capitalize, **ia
|
|
590
600
|
end
|
|
591
601
|
end
|
|
592
602
|
end
|
|
593
603
|
end
|
|
594
604
|
|
|
595
|
-
commands_under
|
|
605
|
+
commands_under %i[admin nodes] do
|
|
596
606
|
command :shared_folders, description: 'Manage shared folders',
|
|
597
607
|
arguments: [{name: :node_id, type: :identifier, lookup: :lookup_node_id}],
|
|
598
608
|
setup: :setup_admin_nodes_shared_folders
|
|
599
609
|
end
|
|
600
610
|
|
|
601
611
|
# admin > nodes > shared_folders sub-tree
|
|
602
|
-
|
|
603
|
-
|
|
612
|
+
# entity: :sf_entity is resolved at runtime from ctx (injected by setup_admin_nodes_shared_folders).
|
|
613
|
+
commands_under %i[admin nodes shared_folders] do
|
|
614
|
+
crud_commands entity: :sf_entity,
|
|
615
|
+
api: :@api_v5,
|
|
616
|
+
name: 'shared folder',
|
|
617
|
+
lookup: :lookup_sf_id,
|
|
618
|
+
items_key: 'shared_folders'
|
|
604
619
|
command :user, description: 'Custom access users',
|
|
605
620
|
arguments: [{name: :sf_id, type: :identifier, lookup: :lookup_sf_id}],
|
|
606
621
|
setup: :setup_admin_nodes_shared_folders_user
|
|
607
622
|
end
|
|
608
623
|
|
|
609
624
|
# admin > nodes > shared_folders > user sub-tree (custom access users)
|
|
610
|
-
|
|
611
|
-
|
|
625
|
+
# entity: :user_path is resolved at runtime from ctx (injected by setup_admin_nodes_shared_folders_user).
|
|
626
|
+
commands_under %i[admin nodes shared_folders user] do
|
|
627
|
+
crud_commands entity: :user_path, api: :@api_v5, name: 'custom access user', lookup: :lookup_sf_user_id, items_key: 'users'
|
|
612
628
|
end
|
|
613
629
|
|
|
614
|
-
|
|
630
|
+
# `members` and `saml_groups`
|
|
615
631
|
CRUD_NO_SHOW = %i[create list modify delete].freeze
|
|
616
632
|
CRUD_NO_LIST = %i[create modify delete show].freeze
|
|
617
633
|
|
|
634
|
+
RES_SINGULAR = {shared_inboxes: :shared_inbox, workgroups: :workgroup}.freeze
|
|
635
|
+
private_constant :RES_SINGULAR
|
|
636
|
+
|
|
618
637
|
# admin > shared_inboxes|workgroups > members|saml_groups|invite_external_collaborator:
|
|
619
638
|
# res_id consumed via arguments:(:identifier) + lookup:, builds res_instance_path for all children
|
|
620
639
|
%i[shared_inboxes workgroups].each do |res|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
640
|
+
lookup_res_id = ->(field, value, **) { @api_v5.lookup_entity_by_field(entity: res.to_s, field: field, value: value, query: {'all': true})['id'] }
|
|
641
|
+
commands_under [:admin, res] do
|
|
642
|
+
command :members, description: 'Members',
|
|
643
|
+
arguments: [{name: :"#{RES_SINGULAR[res]}_id", type: :identifier, lookup: lookup_res_id}],
|
|
644
|
+
setup: :"setup_admin_#{res}_instance"
|
|
645
|
+
command :saml_groups, description: 'Saml groups',
|
|
646
|
+
arguments: [{name: :"#{RES_SINGULAR[res]}_id", type: :identifier, lookup: lookup_res_id}],
|
|
647
|
+
setup: :"setup_admin_#{res}_instance"
|
|
648
|
+
command :invite_external_collaborator, description: 'Invite external collaborator',
|
|
649
|
+
arguments: [{name: :"#{RES_SINGULAR[res]}_id", type: :identifier, lookup: lookup_res_id},
|
|
650
|
+
{name: :input_data, type: Hash}]
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
commands_under [:admin, res, :members] do
|
|
654
|
+
CRUD_NO_SHOW.each do |c|
|
|
655
|
+
args =
|
|
656
|
+
if c.eql?(:create)
|
|
630
657
|
{arguments: [{name: :users, bulk: true}, {name: :access, mandatory: false, default: :standard}]}
|
|
658
|
+
elsif Operations::INSTANCE.include?(c)
|
|
659
|
+
{arguments: [{name: :member_id, type: :identifier, lookup: :"lookup_#{res}_members_id"}]}
|
|
631
660
|
else
|
|
632
661
|
{}
|
|
633
662
|
end
|
|
634
|
-
|
|
635
|
-
end
|
|
663
|
+
command c, description: c.to_s.capitalize, **args
|
|
636
664
|
end
|
|
637
665
|
end
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
666
|
+
|
|
667
|
+
commands_under [:admin, res, :saml_groups] do
|
|
668
|
+
crud_commands entity: :saml_groups_path,
|
|
669
|
+
api: :@api_v5,
|
|
670
|
+
name: 'SAML group',
|
|
671
|
+
operations: CRUD_NO_SHOW,
|
|
672
|
+
lookup: :"lookup_#{res}_saml_groups_id",
|
|
673
|
+
items_key: 'groups'
|
|
642
674
|
end
|
|
643
675
|
end
|
|
644
676
|
|
|
645
|
-
commands_under
|
|
646
|
-
command :show, description: 'Show configuration', action: ->{Result::SingleObject.new(@api_v5.read('configuration'))}
|
|
647
|
-
command
|
|
648
|
-
:modify, description: 'Modify configuration',
|
|
677
|
+
commands_under %i[admin configuration] do
|
|
678
|
+
command :show, description: 'Show configuration', action: -> { Result::SingleObject.new(@api_v5.read('configuration')) }
|
|
679
|
+
command :modify, description: 'Modify configuration',
|
|
649
680
|
arguments: [{name: :input_data, type: Hash}],
|
|
650
|
-
action: ->(input_data:, **){Result::SingleObject.new(@api_v5.update('configuration', input_data))}
|
|
651
|
-
)
|
|
681
|
+
action: ->(input_data:, **) { Result::SingleObject.new(@api_v5.update('configuration', input_data)) }
|
|
652
682
|
end
|
|
653
683
|
|
|
654
|
-
commands_under
|
|
655
|
-
command :show, description: 'Show SMTP configuration', action: ->{Result::SingleObject.new(@api_v5.read('configuration/smtp'))}
|
|
656
|
-
command
|
|
657
|
-
:create, description: 'Create SMTP configuration',
|
|
684
|
+
commands_under %i[admin smtp] do
|
|
685
|
+
command :show, description: 'Show SMTP configuration', action: -> { Result::SingleObject.new(@api_v5.read('configuration/smtp')) }
|
|
686
|
+
command :create, description: 'Create SMTP configuration',
|
|
658
687
|
arguments: [{name: :input_data, type: Hash}],
|
|
659
|
-
action: ->(input_data:, **){Result::SingleObject.new(@api_v5.create('configuration/smtp', input_data))}
|
|
660
|
-
|
|
661
|
-
command(
|
|
662
|
-
:modify, description: 'Modify SMTP configuration',
|
|
688
|
+
action: ->(input_data:, **) { Result::SingleObject.new(@api_v5.create('configuration/smtp', input_data)) }
|
|
689
|
+
command :modify, description: 'Modify SMTP configuration',
|
|
663
690
|
arguments: [{name: :input_data, type: Hash}],
|
|
664
|
-
action: ->(input_data:, **){Result::SingleObject.new(@api_v5.update('configuration/smtp', input_data))}
|
|
691
|
+
action: ->(input_data:, **) { Result::SingleObject.new(@api_v5.update('configuration/smtp', input_data)) }
|
|
692
|
+
command(
|
|
693
|
+
:delete, description: 'Delete SMTP configuration',
|
|
694
|
+
action: lambda do
|
|
695
|
+
@api_v5.delete('configuration/smtp')
|
|
696
|
+
Result::Status.new('SMTP configuration deleted')
|
|
697
|
+
end
|
|
665
698
|
)
|
|
666
|
-
command(:delete, description: 'Delete SMTP configuration', action: lambda do
|
|
667
|
-
@api_v5.delete('configuration/smtp')
|
|
668
|
-
Result::Status.new('SMTP configuration deleted')
|
|
669
|
-
end)
|
|
670
699
|
command :test, description: 'Test SMTP configuration',
|
|
671
700
|
arguments: [{name: :test_data, type: nil}]
|
|
672
701
|
end
|
|
673
702
|
|
|
674
|
-
commands_under
|
|
675
|
-
command(
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
703
|
+
commands_under %i[admin events] do
|
|
704
|
+
command(
|
|
705
|
+
:application, description: 'List application events',
|
|
706
|
+
action: lambda do
|
|
707
|
+
list, total = @api_v5.list_entities_limit_offset_total_count(entity: 'application_events', query: query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::FASPEX, 'application_events')))
|
|
708
|
+
Result::ObjectList.new(list, total: total, fields: %w[event_type created_at application user.name])
|
|
709
|
+
end
|
|
710
|
+
)
|
|
711
|
+
command(
|
|
712
|
+
:webhook, description: 'List webhook events',
|
|
713
|
+
action: lambda do
|
|
714
|
+
list, total = @api_v5.list_entities_limit_offset_total_count(entity: 'all_webhooks_events', query: query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::FASPEX, 'all_webhooks_events')), items_key: 'events')
|
|
715
|
+
Result::ObjectList.new(list, total: total)
|
|
716
|
+
end
|
|
717
|
+
)
|
|
683
718
|
end
|
|
684
719
|
|
|
685
720
|
# admin > clean_deleted handler (leaf, no sub-commands)
|
|
@@ -705,19 +740,6 @@ module Aspera
|
|
|
705
740
|
end
|
|
706
741
|
end
|
|
707
742
|
|
|
708
|
-
# admin > <resource> > create / modify / delete / show
|
|
709
|
-
Api::Faspex::ADMIN_RESOURCES.each do |res|
|
|
710
|
-
CRUD_NO_LIST.each do |op|
|
|
711
|
-
define_action_method([:admin, res, op]) do |input_data: nil, res_id: nil, **|
|
|
712
|
-
args = res_exec_args(res)
|
|
713
|
-
is_bulk = options.get_option(:bulk)
|
|
714
|
-
items = input_data
|
|
715
|
-
items = [items] if items && !items.is_a?(Array)
|
|
716
|
-
entity_execute(command: op, input_data: items, res_id: res_id, is_bulk: is_bulk, bfail: options.get_option(:bfail), **args){ |f, v| res_lookup_id(res, f, v)}
|
|
717
|
-
end
|
|
718
|
-
end
|
|
719
|
-
end
|
|
720
|
-
|
|
721
743
|
def action_admin_smtp_test(test_data:, **)
|
|
722
744
|
test_data = {test_email_recipient: test_data} if test_data.is_a?(String)
|
|
723
745
|
creation = @api_v5.create('configuration/smtp/test', test_data)
|
|
@@ -754,17 +776,15 @@ module Aspera
|
|
|
754
776
|
end
|
|
755
777
|
|
|
756
778
|
# Lookup shared folder id by field/value within a node's shared_folders entity.
|
|
757
|
-
#
|
|
758
|
-
# sf_entity is available in ctx because setup_admin_nodes_shared_folders ran first (Phase A of parent).
|
|
779
|
+
# sf_entity is in ctx from setup_admin_nodes_shared_folders (Phase A of parent).
|
|
759
780
|
def lookup_sf_id(field, value, sf_entity:, **)
|
|
760
781
|
@api_v5.lookup_entity_by_field(entity: sf_entity, items_key: 'shared_folders', field: field, value: value)['id']
|
|
761
782
|
end
|
|
762
783
|
|
|
763
|
-
#
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
end
|
|
784
|
+
# Lookup custom access user id by field/value within a shared folder's users entity.
|
|
785
|
+
# user_path is in ctx from setup_admin_nodes_shared_folders_user (Phase A of parent).
|
|
786
|
+
def lookup_sf_user_id(field, value, user_path:, **)
|
|
787
|
+
@api_v5.lookup_entity_by_field(entity: user_path, items_key: 'users', field: field, value: value)['id']
|
|
768
788
|
end
|
|
769
789
|
|
|
770
790
|
# admin > nodes > shared_folders > user — sf_id: already in ctx via arguments: on the :user command
|
|
@@ -772,17 +792,14 @@ module Aspera
|
|
|
772
792
|
{user_path: "#{sf_entity}/#{sf_id}/custom_access_users"}
|
|
773
793
|
end
|
|
774
794
|
|
|
775
|
-
# admin > nodes > shared_folders > user > create/modify/delete/show/list (custom access users)
|
|
776
|
-
Operations::ALL.each do |op|
|
|
777
|
-
define_action_method([:admin, :nodes, :shared_folders, :user, op]) do |user_path:, **|
|
|
778
|
-
entity_execute(api: @api_v5, entity: user_path, items_key: 'users', command: op){ |f, v| @api_v5.lookup_entity_by_field(entity: user_path, items_key: 'users', field: f, value: v)['id']}
|
|
779
|
-
end
|
|
780
|
-
end
|
|
781
|
-
|
|
782
795
|
# admin > shared_inboxes|workgroups — res_id: already in ctx via arguments: on the :members|:saml_groups command
|
|
783
796
|
%i[shared_inboxes workgroups].each do |res|
|
|
784
|
-
define_method(:"setup_admin_#{res}_instance") do |
|
|
785
|
-
|
|
797
|
+
define_method(:"setup_admin_#{res}_instance") do |**kwargs|
|
|
798
|
+
res_id = kwargs[:"#{RES_SINGULAR[res]}_id"]
|
|
799
|
+
{
|
|
800
|
+
res_instance_path: "#{res}/#{res_id}",
|
|
801
|
+
saml_groups_path: "#{res}/#{res_id}/saml_groups"
|
|
802
|
+
}
|
|
786
803
|
end
|
|
787
804
|
end
|
|
788
805
|
|
|
@@ -800,37 +817,46 @@ module Aspera
|
|
|
800
817
|
end
|
|
801
818
|
end
|
|
802
819
|
|
|
803
|
-
#
|
|
820
|
+
# Lookup methods for members/saml_groups identity resolution (used by arguments: lookup:)
|
|
821
|
+
# res_instance_path is in ctx from setup_admin_{res}_instance (Phase A of parent).
|
|
804
822
|
%i[shared_inboxes workgroups].each do |res|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
823
|
+
define_method(:"lookup_#{res}_members_id") do |field, value, res_instance_path:, **|
|
|
824
|
+
res_path = "#{res_instance_path}/members"
|
|
825
|
+
@api_v5.lookup_entity_by_field(entity: res_path, field: field, value: value, query: Rest.php_style({type: %w[user]}))['user_id']
|
|
826
|
+
end
|
|
827
|
+
define_method(:"lookup_#{res}_saml_groups_id") do |field, value, res_instance_path:, **|
|
|
828
|
+
res_path = "#{res_instance_path}/saml_groups"
|
|
829
|
+
@api_v5.lookup_entity_by_field(entity: res_path, field: field, value: value, query: Rest.php_style({type: %w[user]}))['user_id']
|
|
830
|
+
end
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
# admin > shared_inboxes|workgroups > members > create/list/modify/delete
|
|
834
|
+
# (saml_groups CRUD is handled by crud_commands)
|
|
835
|
+
%i[shared_inboxes workgroups].each do |res|
|
|
836
|
+
define_action_method([:admin, res, :members, :list]) do |res_instance_path:, **|
|
|
837
|
+
entity_list(api: @api_v5, entity: "#{res_instance_path}/members", items_key: 'members')
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
define_action_method([:admin, res, :members, :modify]) do |res_instance_path:, **kwargs|
|
|
841
|
+
entity_modify(api: @api_v5, entity: "#{res_instance_path}/members", id: kwargs[:member_id])
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
define_action_method([:admin, res, :members, :delete]) do |res_instance_path:, **kwargs|
|
|
845
|
+
entity_delete(api: @api_v5, entity: "#{res_instance_path}/members", id: kwargs[:member_id])
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
define_action_method([:admin, res, :members, :create]) do |users:, access:, res_instance_path:, **|
|
|
849
|
+
res_path = "#{res_instance_path}/members"
|
|
850
|
+
resolved = resolve_member_user_ids(users)
|
|
851
|
+
input_data = [{user: resolved.map { |u| {id: u, access: access} }}]
|
|
852
|
+
entity_create(api: @api_v5, entity: res_path, input_data: input_data)
|
|
827
853
|
end
|
|
828
854
|
end
|
|
829
855
|
|
|
830
856
|
# admin > shared_inboxes|workgroups > invite_external_collaborator
|
|
831
857
|
%i[shared_inboxes workgroups].each do |res|
|
|
832
|
-
define_action_method([:admin, res, :invite_external_collaborator]) do |input_data:,
|
|
833
|
-
res_instance_path = "#{res}/#{
|
|
858
|
+
define_action_method([:admin, res, :invite_external_collaborator]) do |input_data:, **kwargs|
|
|
859
|
+
res_instance_path = "#{res}/#{kwargs[:"#{RES_SINGULAR[res]}_id"]}"
|
|
834
860
|
result = @api_v5.create("#{res_instance_path}/external_collaborator", input_data)
|
|
835
861
|
formatter.display_status(result['message'])
|
|
836
862
|
Result::SingleObject.new(@api_v5.lookup_entity_by_field(entity: "#{res_instance_path}/members", items_key: 'members', value: input_data['email_address'], query: {}))
|
|
@@ -845,7 +871,7 @@ module Aspera
|
|
|
845
871
|
return {} if @api_v5
|
|
846
872
|
@api_v5 = Api::Faspex.new(**Oauth.kwargs_from_options(options))
|
|
847
873
|
# in case user wants to use HTTPGW tell transfer agent how to get address
|
|
848
|
-
transfer.httpgw_url_cb = lambda{@api_v5.read('account')['gateway_url']}
|
|
874
|
+
transfer.httpgw_url_cb = lambda { @api_v5.read('account')['gateway_url'] }
|
|
849
875
|
{}
|
|
850
876
|
end
|
|
851
877
|
|
|
@@ -856,8 +882,9 @@ module Aspera
|
|
|
856
882
|
{package_id: package_id}
|
|
857
883
|
end
|
|
858
884
|
|
|
859
|
-
def action_packages_list
|
|
860
|
-
list, total = list_packages_with_filter
|
|
885
|
+
def action_packages_list(filter: nil, **)
|
|
886
|
+
list, max_items, total = list_packages_with_filter(filter: filter)
|
|
887
|
+
list = list[0, max_items] if max_items
|
|
861
888
|
fields = %w[id title status sender.name recipients.0.name release_date total_bytes total_files]
|
|
862
889
|
fields.delete('recipients.0.name') if %w[inbox inbox_history].include?(options.get_option(:box))
|
|
863
890
|
fields.delete('sender.name') if %w[outbox outbox_history].include?(options.get_option(:box))
|
|
@@ -866,7 +893,7 @@ module Aspera
|
|
|
866
893
|
|
|
867
894
|
def action_packages_delete(package_id:, **)
|
|
868
895
|
ids = package_id.is_a?(Array) ? package_id : [package_id]
|
|
869
|
-
Aspera.assert_array_all(ids, String){'Package id(s)'}
|
|
896
|
+
Aspera.assert_array_all(ids, String) { 'Package id(s)' }
|
|
870
897
|
# API returns 204, empty on success
|
|
871
898
|
@api_v5.call(
|
|
872
899
|
operation: 'DELETE',
|
|
@@ -899,16 +926,16 @@ module Aspera
|
|
|
899
926
|
# Called via lookup: :lookup_shared_folder_id on the shared_folders > browse command.
|
|
900
927
|
def lookup_shared_folder_id(field, value, **)
|
|
901
928
|
all = @api_v5.read('shared_folders')['shared_folders']
|
|
902
|
-
matches = all.select{ |i| i[field].eql?(value)}
|
|
903
|
-
Aspera.assert(!matches.empty?){"no match for #{field} = #{value}"}
|
|
904
|
-
Aspera.assert(matches.length == 1){"multiple matches for #{field} = #{value}"}
|
|
929
|
+
matches = all.select { |i| i[field].eql?(value) }
|
|
930
|
+
Aspera.assert(!matches.empty?) { "no match for #{field} = #{value}" }
|
|
931
|
+
Aspera.assert(matches.length == 1) { "multiple matches for #{field} = #{value}" }
|
|
905
932
|
matches.first['id']
|
|
906
933
|
end
|
|
907
934
|
|
|
908
935
|
def action_shared_folders_browse(folder_path:, shared_folder_id:, **)
|
|
909
936
|
all_shared_folders = @api_v5.read('shared_folders')['shared_folders']
|
|
910
|
-
node = all_shared_folders.find{ |i| i['id'].eql?(shared_folder_id)}
|
|
911
|
-
Aspera.assert(!node.nil?){"No such shared folder id #{shared_folder_id}"}
|
|
937
|
+
node = all_shared_folders.find { |i| i['id'].eql?(shared_folder_id) }
|
|
938
|
+
Aspera.assert(!node.nil?) { "No such shared folder id #{shared_folder_id}" }
|
|
912
939
|
browse_folder("nodes/#{node['node_id']}/shared_folders/#{shared_folder_id}/browse", {}, folder_path: folder_path)
|
|
913
940
|
end
|
|
914
941
|
|
|
@@ -920,34 +947,18 @@ module Aspera
|
|
|
920
947
|
end
|
|
921
948
|
|
|
922
949
|
def action_invitations_create(input_data:, **)
|
|
923
|
-
|
|
924
|
-
Result.bulk(input_data, is_bulk: is_bulk, command: :create, bfail: options.get_option(:bfail)) do |params|
|
|
950
|
+
bulk_result(input_data, command: :create) do |params|
|
|
925
951
|
endpoint = params.key?('recipient_name') ? 'public_invitations' : 'invitations'
|
|
926
952
|
@api_v5.create(endpoint, params)
|
|
927
953
|
end
|
|
928
954
|
end
|
|
929
955
|
|
|
930
|
-
# CRUD handlers for invitations (list, show, modify, delete)
|
|
931
|
-
Operations::ALL.reject{ |op| op == :create}.each do |op|
|
|
932
|
-
define_action_method([:invitations, op]) do
|
|
933
|
-
entity_execute(
|
|
934
|
-
api: @api_v5,
|
|
935
|
-
entity: 'invitations',
|
|
936
|
-
command: op,
|
|
937
|
-
items_key: 'invitations',
|
|
938
|
-
display_fields: %w[id public recipient_type recipient_name email_address]
|
|
939
|
-
) do |field, value|
|
|
940
|
-
@api_v5.lookup_entity_by_field(entity: 'invitations', field: field, value: value, query: {})['id']
|
|
941
|
-
end
|
|
942
|
-
end
|
|
943
|
-
end
|
|
944
|
-
|
|
945
956
|
def action_gateway(parameters: {}, **)
|
|
946
957
|
require 'aspera/faspex_gw'
|
|
947
958
|
parameters = parameters.symbolize_keys
|
|
948
|
-
uri = URI.parse(parameters.delete(:url){WebServerSimple::DEFAULT_URL})
|
|
959
|
+
uri = URI.parse(parameters.delete(:url) { WebServerSimple::DEFAULT_URL })
|
|
949
960
|
server = WebServerSimple.new(uri, **parameters.slice(*WebServerSimple::PARAMS))
|
|
950
|
-
Aspera.assert(parameters.except(*WebServerSimple::PARAMS).empty?){"unexpected parameters: #{parameters.except(*WebServerSimple::PARAMS).keys}"}
|
|
961
|
+
Aspera.assert(parameters.except(*WebServerSimple::PARAMS).empty?) { "unexpected parameters: #{parameters.except(*WebServerSimple::PARAMS).keys}" }
|
|
951
962
|
server.mount(uri.path, Faspex4GWServlet, @api_v5, nil)
|
|
952
963
|
server.start
|
|
953
964
|
Result::Status.new('Gateway terminated')
|
|
@@ -956,7 +967,7 @@ module Aspera
|
|
|
956
967
|
def action_postprocessing(parameters: {}, **)
|
|
957
968
|
require 'aspera/faspex_postproc' # cspell:disable-line
|
|
958
969
|
parameters = parameters.symbolize_keys
|
|
959
|
-
uri = URI.parse(parameters.delete(:url){WebServerSimple::DEFAULT_URL})
|
|
970
|
+
uri = URI.parse(parameters.delete(:url) { WebServerSimple::DEFAULT_URL })
|
|
960
971
|
parameters[:root] = uri.path
|
|
961
972
|
server = WebServerSimple.new(uri, **parameters.slice(*WebServerSimple::PARAMS))
|
|
962
973
|
server.mount(uri.path, Faspex4PostProcServlet, parameters.except(*WebServerSimple::PARAMS))
|
|
@@ -969,7 +980,7 @@ module Aspera
|
|
|
969
980
|
CONTACT_TYPES = (WORKGROUP_TYPES + %w{distribution_list user external_user}).freeze
|
|
970
981
|
PACKAGE_RECIPIENT_TYPES = %i{recipients private_recipients notified_on_upload notified_on_download notified_on_receipt}
|
|
971
982
|
private_constant :SHARED_INBOX_MEMBER_LEVELS, :ACCOUNT_TYPES, :CONTACT_TYPES, :PACKAGE_RECIPIENT_TYPES,
|
|
972
|
-
:
|
|
983
|
+
:CRUD_NO_SHOW, :CRUD_NO_LIST
|
|
973
984
|
end
|
|
974
985
|
end
|
|
975
986
|
end
|