aspera-cli 4.27.1 → 4.27.3
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 +67 -1
- data/bin/ascli +2 -1
- data/docs/README.md +805 -747
- data/lib/aspera/agent/connect.rb +6 -4
- data/lib/aspera/agent/desktop.rb +2 -2
- data/lib/aspera/agent/direct.rb +3 -1
- data/lib/aspera/agent/node.rb +3 -3
- data/lib/aspera/api/alee.rb +1 -1
- data/lib/aspera/api/aoc.rb +14 -12
- data/lib/aspera/api/ats.rb +1 -1
- data/lib/aspera/api/cos_node.rb +2 -2
- data/lib/aspera/api/faspex.rb +9 -7
- data/lib/aspera/api/httpgw.rb +37 -33
- data/lib/aspera/api/node.rb +38 -33
- data/lib/aspera/ascmd.rb +3 -1
- data/lib/aspera/ascp/installation.rb +62 -27
- data/lib/aspera/ascp/management.rb +1 -0
- data/lib/aspera/assert.rb +4 -0
- data/lib/aspera/cli/ascp_actions.rb +20 -41
- data/lib/aspera/cli/async_transfer_store.rb +2 -2
- data/lib/aspera/cli/bootstrapper.rb +11 -15
- data/lib/aspera/cli/command_line.rb +252 -0
- data/lib/aspera/cli/command_registry.rb +149 -33
- data/lib/aspera/cli/command_spec.rb +103 -14
- data/lib/aspera/cli/completion/ascli.bash +12 -0
- data/lib/aspera/cli/completion/ascli.fish +16 -0
- data/lib/aspera/cli/completion/ascli.zsh +19 -0
- data/lib/aspera/cli/context.rb +3 -0
- data/lib/aspera/cli/deprecation.rb +37 -0
- data/lib/aspera/cli/extended_value.rb +2 -0
- data/lib/aspera/cli/formatter.rb +87 -75
- data/lib/aspera/cli/gem_checker.rb +1 -1
- data/lib/aspera/cli/hints.rb +7 -6
- data/lib/aspera/cli/http.rb +21 -21
- data/lib/aspera/cli/info.rb +3 -0
- data/lib/aspera/cli/mcp_tool.rb +47 -83
- data/lib/aspera/cli/option_declarator.rb +33 -42
- data/lib/aspera/cli/option_registry.rb +69 -0
- data/lib/aspera/cli/option_types.rb +103 -0
- data/lib/aspera/cli/option_value.rb +281 -0
- data/lib/aspera/cli/options.schema.yaml +38 -5
- data/lib/aspera/cli/parser.rb +307 -848
- data/lib/aspera/cli/plugins/alee.rb +7 -4
- data/lib/aspera/cli/plugins/aoc.rb +435 -380
- data/lib/aspera/cli/plugins/ats.rb +58 -73
- data/lib/aspera/cli/plugins/base.rb +190 -240
- data/lib/aspera/cli/plugins/basic_auth.rb +2 -10
- data/lib/aspera/cli/plugins/config.rb +244 -178
- data/lib/aspera/cli/plugins/console.rb +102 -38
- data/lib/aspera/cli/plugins/cos.rb +6 -23
- data/lib/aspera/cli/plugins/factory.rb +3 -0
- data/lib/aspera/cli/plugins/faspex5.rb +176 -173
- data/lib/aspera/cli/plugins/faspio.rb +5 -10
- data/lib/aspera/cli/plugins/httpgw.rb +8 -11
- data/lib/aspera/cli/plugins/mcp.rb +20 -55
- data/lib/aspera/cli/plugins/node.rb +277 -311
- data/lib/aspera/cli/plugins/orchestrator.rb +90 -77
- data/lib/aspera/cli/plugins/preview.rb +79 -90
- data/lib/aspera/cli/plugins/server.rb +76 -50
- data/lib/aspera/cli/plugins/shares.rb +68 -116
- data/lib/aspera/cli/preset_actions.rb +17 -10
- data/lib/aspera/cli/preset_manager.rb +12 -2
- data/lib/aspera/cli/prompt.rb +35 -0
- data/lib/aspera/cli/result.rb +13 -18
- data/lib/aspera/cli/runner.rb +31 -54
- data/lib/aspera/cli/special_values.rb +5 -0
- data/lib/aspera/cli/sync_actions.rb +41 -37
- data/lib/aspera/cli/terminal_formatter.rb +9 -3
- data/lib/aspera/cli/transfer_actions.rb +0 -6
- data/lib/aspera/cli/transfer_agent.rb +29 -35
- data/lib/aspera/cli/vault_manager.rb +0 -17
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +4 -2
- data/lib/aspera/command_line_builder.rb +1 -0
- data/lib/aspera/coverage.rb +1 -0
- data/lib/aspera/environment.rb +7 -1
- data/lib/aspera/faspex_gw.rb +2 -1
- data/lib/aspera/faspex_postproc.rb +1 -0
- data/lib/aspera/graphql.rb +5 -5
- data/lib/aspera/json_rpc/client.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +1 -1
- data/lib/aspera/keychain/one_password_api.rb +1 -1
- data/lib/aspera/link_header.rb +2 -2
- data/lib/aspera/log.rb +22 -25
- data/lib/aspera/markdown.rb +2 -0
- data/lib/aspera/mime.rb +25 -0
- data/lib/aspera/node_simulator.rb +1 -0
- data/lib/aspera/oauth/base.rb +35 -25
- data/lib/aspera/oauth/factory.rb +1 -0
- data/lib/aspera/oauth/generic.rb +1 -1
- data/lib/aspera/oauth/jwt.rb +1 -1
- data/lib/aspera/oauth/web.rb +9 -8
- data/lib/aspera/preview/file_types.rb +4 -4
- data/lib/aspera/preview/generator.rb +7 -0
- data/lib/aspera/preview/options.rb +4 -4
- data/lib/aspera/preview/terminal.rb +4 -3
- data/lib/aspera/preview/utils.rb +9 -6
- data/lib/aspera/products/connect.rb +1 -1
- data/lib/aspera/rainbow.rb +7 -0
- data/lib/aspera/rest/aspera_errors.rb +60 -0
- data/lib/aspera/rest/call_error.rb +27 -0
- data/lib/aspera/rest/client.rb +514 -0
- data/lib/aspera/rest/error_analyzer.rb +113 -0
- data/lib/aspera/rest/list.rb +143 -0
- data/lib/aspera/rest/parameters.rb +55 -0
- data/lib/aspera/rest/util.rb +176 -0
- data/lib/aspera/rest.rb +7 -621
- data/lib/aspera/schema/IBM Aspera Console-enhanced.yaml +1125 -0
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +39 -0
- data/lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml +2395 -0
- data/lib/aspera/schema/documentation.rb +13 -3
- data/lib/aspera/schema/registry.rb +18 -1
- data/lib/aspera/schema/validator.rb +92 -0
- data/lib/aspera/secret_hider.rb +36 -25
- data/lib/aspera/string_ext.rb +15 -0
- data/lib/aspera/temp_file_manager.rb +6 -5
- data/lib/aspera/transfer/parameters.rb +2 -0
- data/lib/aspera/transfer/spec.rb +1 -0
- data/lib/aspera/transfer/spec.schema.yaml +1 -0
- data/lib/aspera/uri_reader.rb +11 -11
- data/lib/aspera/web_auth/index.html +147 -0
- data/lib/aspera/web_auth/server.rb +81 -0
- data.tar.gz.sig +0 -0
- metadata +39 -7
- metadata.gz.sig +0 -0
- data/lib/aspera/colors.rb +0 -79
- data/lib/aspera/rest_call_error.rb +0 -25
- data/lib/aspera/rest_error_analyzer.rb +0 -111
- data/lib/aspera/rest_errors_aspera.rb +0 -58
- data/lib/aspera/rest_list.rb +0 -136
- data/lib/aspera/web_auth.rb +0 -211
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
require 'aspera/schema/registry'
|
|
6
6
|
require 'aspera/cli/plugins/oauth'
|
|
7
7
|
require 'aspera/cli/extended_value'
|
|
8
|
+
require 'aspera/cli/formatter'
|
|
8
9
|
require 'aspera/transfer/result'
|
|
9
10
|
require 'aspera/cli/special_values'
|
|
10
11
|
require 'aspera/cli/wizard'
|
|
@@ -15,6 +16,8 @@ require 'aspera/nagios'
|
|
|
15
16
|
require 'aspera/environment'
|
|
16
17
|
require 'aspera/assert'
|
|
17
18
|
require 'securerandom'
|
|
19
|
+
require 'aspera/rainbow'
|
|
20
|
+
using Rainbow
|
|
18
21
|
|
|
19
22
|
module Aspera
|
|
20
23
|
module Cli
|
|
@@ -35,7 +38,7 @@ module Aspera
|
|
|
35
38
|
urls.each do |base_url|
|
|
36
39
|
# Faspex is always HTTPS
|
|
37
40
|
next unless base_url.start_with?('https://')
|
|
38
|
-
api = Rest.new(base_url: base_url, redirect_max: 1)
|
|
41
|
+
api = Rest::Client.new(base_url: base_url, redirect_max: 1)
|
|
39
42
|
response = api.read(Api::Faspex::PATH_API_DETECT, ret: :resp)
|
|
40
43
|
next unless response.code.start_with?('2') && response.body.strip.empty?
|
|
41
44
|
# end is at -1, and subtract 1 for "/"
|
|
@@ -96,13 +99,6 @@ module Aspera
|
|
|
96
99
|
option :shared_folder, description: 'Send package with files from shared folder'
|
|
97
100
|
option :group_type, description: 'Type of shared box', allowed: %i[shared_inboxes workgroups], default: :shared_inboxes
|
|
98
101
|
|
|
99
|
-
def initialize(**_)
|
|
100
|
-
super
|
|
101
|
-
options.parse_options!
|
|
102
|
-
# [Aspera::Api::Faspex]
|
|
103
|
-
@api_v5 = nil
|
|
104
|
-
end
|
|
105
|
-
|
|
106
102
|
# if recipient is just an email, then convert to expected API hash : name and type
|
|
107
103
|
def normalize_recipients(parameters, type)
|
|
108
104
|
type = type.to_s
|
|
@@ -117,7 +113,7 @@ module Aspera
|
|
|
117
113
|
parameters[type].map! do |recipient_data|
|
|
118
114
|
# If just a string, make a general lookup and build expected name/type hash
|
|
119
115
|
if recipient_data.is_a?(String)
|
|
120
|
-
matched =
|
|
116
|
+
matched = api_v5.lookup_with_q('contacts', value: recipient_data, query: Rest.php_style({context: 'packages', type: recipient_types}))
|
|
121
117
|
recipient_data = {
|
|
122
118
|
name: matched['name'],
|
|
123
119
|
recipient_type: matched['type']
|
|
@@ -132,7 +128,7 @@ module Aspera
|
|
|
132
128
|
def wait_package_status(id, status_list: Api::Faspex::PACKAGE_TERMINATED)
|
|
133
129
|
total_sent = false
|
|
134
130
|
loop do
|
|
135
|
-
status =
|
|
131
|
+
status = api_v5.read("packages/#{id}/upload_details")
|
|
136
132
|
status['id'] = id
|
|
137
133
|
# user asked to not follow
|
|
138
134
|
return status if status_list.nil?
|
|
@@ -159,12 +155,12 @@ module Aspera
|
|
|
159
155
|
def wait_for_job(job_id)
|
|
160
156
|
result = nil
|
|
161
157
|
loop do
|
|
162
|
-
result =
|
|
158
|
+
result = api_v5.read("jobs/#{job_id}", {type: :formatted})
|
|
163
159
|
break unless Api::Faspex::JOB_RUNNING.include?(result['status'])
|
|
164
|
-
|
|
160
|
+
Rest::Parameters.instance.spinner_cb.call(result['status'])
|
|
165
161
|
sleep(0.5)
|
|
166
162
|
end
|
|
167
|
-
|
|
163
|
+
Rest::Parameters.instance.spinner_cb.call(action: :success)
|
|
168
164
|
return result
|
|
169
165
|
end
|
|
170
166
|
|
|
@@ -185,21 +181,21 @@ module Aspera
|
|
|
185
181
|
when *Api::Faspex::API_LIST_MAILBOX_TYPES then "#{box}/packages"
|
|
186
182
|
else
|
|
187
183
|
group_type = options.get_option(:group_type)
|
|
188
|
-
"#{group_type}/#{
|
|
184
|
+
"#{group_type}/#{api_v5.lookup_entity_by_field(entity: group_type, value: box)['id']}/packages"
|
|
189
185
|
end
|
|
190
186
|
# Merge default query with user-provided query: user values take precedence, but defaults are preserved
|
|
191
187
|
user_query = query_read_delete(schema: Schema::Registry.query_params(Schema::Registry::FASPEX, 'packages'))
|
|
192
188
|
merged_query = user_query.nil? ? query.dup : query.merge(user_query)
|
|
193
189
|
# Extract `max` before the API call so callers can apply it after post-API filtering
|
|
194
|
-
max_items = merged_query.delete(
|
|
195
|
-
list, total =
|
|
190
|
+
max_items = merged_query.delete(Rest::List::MAX_ITEMS)&.to_i
|
|
191
|
+
list, total = api_v5.list_entities_limit_offset_total_count(entity: entity, query: merged_query)
|
|
196
192
|
return list.select(&filter), max_items, total
|
|
197
193
|
end
|
|
198
194
|
|
|
199
195
|
# Build query to get package recipients based on package info in case of shared inbox or workgroup recipient
|
|
200
196
|
# @param package_id [String] the package id to get info from
|
|
201
197
|
def recipient_query(package_id)
|
|
202
|
-
package_info =
|
|
198
|
+
package_info = api_v5.read("packages/#{package_id}")
|
|
203
199
|
base_query = {}
|
|
204
200
|
base_query['recipient_workgroup_id'] = package_info['recipients'].first['id'] if WORKGROUP_TYPES.include?(package_info['recipients'].first['recipient_type'])
|
|
205
201
|
base_query['recipient_user_id'] = package_info['recipients'].first['id'] if package_info['recipients'].first['recipient_type'].eql?('user')
|
|
@@ -242,7 +238,7 @@ module Aspera
|
|
|
242
238
|
# a single id was provided, or a list of ids
|
|
243
239
|
package_ids = [package_ids] unless package_ids.is_a?(Array)
|
|
244
240
|
Aspera.assert_array_all(package_ids, String) { 'Package id(s)' }
|
|
245
|
-
# packages = package_ids.map{|pkg_id
|
|
241
|
+
# packages = package_ids.map{|pkg_id|api_v5.read("packages/#{pkg_id}")}
|
|
246
242
|
packages = package_ids.map { |pkg_id| {'id'=>pkg_id} }
|
|
247
243
|
end
|
|
248
244
|
result_transfer = []
|
|
@@ -257,12 +253,12 @@ module Aspera
|
|
|
257
253
|
type: Api::Faspex.box_type(box),
|
|
258
254
|
transfer_type: Api::Faspex::TRANSFER_CONNECT
|
|
259
255
|
}
|
|
260
|
-
# download_params[:recipient_workgroup_id] =
|
|
256
|
+
# download_params[:recipient_workgroup_id] = api_v5.lookup_entity_by_field(entity: options.get_option(:group_type), value: box)['id'] if !Api::Faspex::API_LIST_MAILBOX_TYPES.include?(box) && box != SpecialValues::ALL
|
|
261
257
|
packages.each do |package|
|
|
262
258
|
pkg_id = package['id']
|
|
263
259
|
formatter.display_status("Receiving package #{pkg_id}")
|
|
264
260
|
# TODO: allow from sent as well ?
|
|
265
|
-
transfer_spec =
|
|
261
|
+
transfer_spec = api_v5.call(
|
|
266
262
|
operation: 'POST',
|
|
267
263
|
subpath: "packages/#{pkg_id}/transfer_spec/download",
|
|
268
264
|
query: download_params.merge(recipient_query(pkg_id)),
|
|
@@ -285,10 +281,10 @@ module Aspera
|
|
|
285
281
|
|
|
286
282
|
def package_send(parameters)
|
|
287
283
|
# autofill recipient for public url
|
|
288
|
-
if
|
|
284
|
+
if api_v5.pub_link_context&.key?('recipient_type') && !parameters.key?('recipients')
|
|
289
285
|
parameters['recipients'] = [{
|
|
290
|
-
name:
|
|
291
|
-
recipient_type:
|
|
286
|
+
name: api_v5.pub_link_context['name'],
|
|
287
|
+
recipient_type: api_v5.pub_link_context['recipient_type']
|
|
292
288
|
}]
|
|
293
289
|
end
|
|
294
290
|
PACKAGE_RECIPIENT_TYPES.each { |type| normalize_recipients(parameters, type) }
|
|
@@ -298,11 +294,11 @@ module Aspera
|
|
|
298
294
|
transfer.user_transfer_spec.delete('content_protection')
|
|
299
295
|
parameters['ear_enabled'] = true
|
|
300
296
|
end
|
|
301
|
-
package =
|
|
297
|
+
package = api_v5.create('packages', parameters)
|
|
302
298
|
shared_folder = options.get_option(:shared_folder)
|
|
303
299
|
if shared_folder.nil?
|
|
304
300
|
# send from local files
|
|
305
|
-
transfer_spec =
|
|
301
|
+
transfer_spec = api_v5.create(
|
|
306
302
|
"packages/#{package['id']}/transfer_spec/upload",
|
|
307
303
|
{paths: transfer.source_list},
|
|
308
304
|
query: {transfer_type: Api::Faspex::TRANSFER_CONNECT}
|
|
@@ -313,7 +309,7 @@ module Aspera
|
|
|
313
309
|
else
|
|
314
310
|
# send from remote shared folder
|
|
315
311
|
if (m = Parser.percent_selector(shared_folder))
|
|
316
|
-
shared_folder =
|
|
312
|
+
shared_folder = api_v5.lookup_entity_by_field(
|
|
317
313
|
entity: 'shared_folders',
|
|
318
314
|
field: m[:field],
|
|
319
315
|
value: m[:value]
|
|
@@ -321,7 +317,7 @@ module Aspera
|
|
|
321
317
|
end
|
|
322
318
|
transfer_request = {shared_folder_id: shared_folder, paths: transfer.source_list}
|
|
323
319
|
# start remote transfer and get first status
|
|
324
|
-
result =
|
|
320
|
+
result = api_v5.create("packages/#{package['id']}/remote_transfer", transfer_request)
|
|
325
321
|
result['id'] = package['id']
|
|
326
322
|
unless result['status'].eql?('completed')
|
|
327
323
|
formatter.display_status("Package #{package['id']}")
|
|
@@ -341,7 +337,7 @@ module Aspera
|
|
|
341
337
|
Aspera.assert_type(filters, Hash)
|
|
342
338
|
filters['basenames'] ||= []
|
|
343
339
|
Aspera.assert_type(filters, Hash) { 'filters' }
|
|
344
|
-
max_items = query.delete(
|
|
340
|
+
max_items = query.delete(Rest::List::MAX_ITEMS)
|
|
345
341
|
recursive = query.delete('recursive')
|
|
346
342
|
use_paging = query.delete('paging') { true }
|
|
347
343
|
if use_paging
|
|
@@ -356,7 +352,7 @@ module Aspera
|
|
|
356
352
|
until folders_to_process.empty?
|
|
357
353
|
path = folders_to_process.shift
|
|
358
354
|
loop do
|
|
359
|
-
data, http =
|
|
355
|
+
data, http = api_v5.call(
|
|
360
356
|
operation: 'POST',
|
|
361
357
|
subpath: browse_endpoint,
|
|
362
358
|
query: query,
|
|
@@ -380,49 +376,49 @@ module Aspera
|
|
|
380
376
|
break if data['item_count'].eql?(0)
|
|
381
377
|
query['offset'] += data['item_count']
|
|
382
378
|
end
|
|
383
|
-
|
|
379
|
+
Rest::Parameters.instance.spinner_cb.call(all_items.count)
|
|
384
380
|
end
|
|
385
381
|
query.delete('iteration_token')
|
|
386
382
|
end
|
|
387
|
-
|
|
383
|
+
Rest::Parameters.instance.spinner_cb.call(action: :success)
|
|
388
384
|
return Result::ObjectList.new(all_items, total: total_count)
|
|
389
385
|
end
|
|
390
386
|
|
|
391
387
|
# Per-resource configuration for admin CRUD sub-trees.
|
|
392
|
-
# Keys mirror entity_list/show/create/modify/delete kwargs; extra_commands
|
|
388
|
+
# Keys mirror entity_list/show/create/modify/delete kwargs; extra_commands declares additional leaf commands: {name => command attributes}.
|
|
393
389
|
# @return [Hash{Symbol => Hash}]
|
|
394
390
|
RESOURCE_CONFIG = {
|
|
395
391
|
accounts: {
|
|
396
|
-
display_fields:
|
|
397
|
-
extra_commands:
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
body_component: Schema::Registry::FASPEX
|
|
392
|
+
display_fields: Formatter.all_but('user_profile_data_attributes'),
|
|
393
|
+
extra_commands: {reset_password: {description: 'Send password reset email to account', arguments: [{name: :account_id, type: :identifier, lookup: ->(field, value, **) { res_lookup_id(:accounts, field, value) }}]}},
|
|
394
|
+
query_component: Schema::Registry::FASPEX,
|
|
395
|
+
body_component: Schema::Registry::FASPEX
|
|
401
396
|
},
|
|
402
397
|
alternate_addresses: {entity: 'configuration/alternate_addresses', query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
403
398
|
contacts: {query_component: Schema::Registry::FASPEX},
|
|
404
399
|
distribution_lists: {entity: 'account/distribution_lists', delete_style: 'ids', query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
405
400
|
email_notifications: {id_as_arg: 'type', query_component: Schema::Registry::FASPEX},
|
|
406
401
|
file_processing: {
|
|
407
|
-
commands: %i[
|
|
402
|
+
commands: %i[modify],
|
|
403
|
+
extra_commands: {next: {description: 'List next files to process'}},
|
|
408
404
|
body_component: Schema::Registry::FASPEX,
|
|
409
405
|
is_singleton: true
|
|
410
406
|
},
|
|
411
407
|
jobs: {display_fields: %w[id job_name job_type status], query_component: Schema::Registry::FASPEX},
|
|
412
408
|
metadata_profiles: {entity: 'configuration/metadata_profiles', items_key: 'profiles', query_component: Schema::Registry::FASPEX, body_component: Schema::Registry::FASPEX},
|
|
413
409
|
nodes: {
|
|
414
|
-
extra_commands:
|
|
415
|
-
instance_arg_commands: {
|
|
410
|
+
extra_commands: {
|
|
416
411
|
browse: {
|
|
417
|
-
|
|
418
|
-
|
|
412
|
+
description: 'Browse files of node',
|
|
413
|
+
arguments: [{name: :node_id, type: :identifier, lookup: :lookup_node_id},
|
|
414
|
+
{name: :folder_path, mandatory: false, default: '/'}]
|
|
419
415
|
}
|
|
420
416
|
},
|
|
421
|
-
query_component:
|
|
422
|
-
body_component:
|
|
417
|
+
query_component: Schema::Registry::FASPEX,
|
|
418
|
+
body_component: Schema::Registry::FASPEX
|
|
423
419
|
},
|
|
424
420
|
oauth_clients: {
|
|
425
|
-
display_fields:
|
|
421
|
+
display_fields: Formatter.all_but('public_key'),
|
|
426
422
|
api: -> { Api::Faspex.new(root: Api::Faspex::PATH_AUTH, **Oauth.kwargs_from_options(options)) },
|
|
427
423
|
list_query: {'expand': true, 'no_api_path': true, 'client_types[]': 'public'},
|
|
428
424
|
query_component: Schema::Registry::FASPEX,
|
|
@@ -446,7 +442,7 @@ module Aspera
|
|
|
446
442
|
def res_exec_args(res_sym)
|
|
447
443
|
cfg = RESOURCE_CONFIG.fetch(res_sym, {})
|
|
448
444
|
{
|
|
449
|
-
api: resource_config_value(cfg, :api) ||
|
|
445
|
+
api: resource_config_value(cfg, :api) || api_v5,
|
|
450
446
|
entity: resource_config_value(cfg, :entity) || res_sym.to_s,
|
|
451
447
|
items_key: resource_config_value(cfg, :items_key),
|
|
452
448
|
delete_style: resource_config_value(cfg, :delete_style),
|
|
@@ -461,7 +457,7 @@ module Aspera
|
|
|
461
457
|
|
|
462
458
|
# admin > nodes — lookup node id by field/value
|
|
463
459
|
def lookup_node_id(field, value, **)
|
|
464
|
-
|
|
460
|
+
api_v5.lookup_entity_by_field(entity: 'nodes', field: field, value: value)['id']
|
|
465
461
|
end
|
|
466
462
|
|
|
467
463
|
# Lookup id for a RESOURCE_CONFIG resource by field/value.
|
|
@@ -470,7 +466,7 @@ module Aspera
|
|
|
470
466
|
entity = resource_config_value(cfg, :entity) || res_sym.to_s
|
|
471
467
|
items_key = resource_config_value(cfg, :items_key)
|
|
472
468
|
res_id_query = resource_config_value(cfg, :res_id_query) || :default
|
|
473
|
-
|
|
469
|
+
api_v5.lookup_entity_by_field(entity: entity, value: value, field: field, items_key: items_key, query: res_id_query)['id']
|
|
474
470
|
end
|
|
475
471
|
|
|
476
472
|
# Dynamically define lookup methods for admin resources (used by crud_commands)
|
|
@@ -482,78 +478,86 @@ module Aspera
|
|
|
482
478
|
|
|
483
479
|
# --- DSL ---
|
|
484
480
|
|
|
485
|
-
#
|
|
486
|
-
# :health and :postprocessing work without authentication, so they have no setup.
|
|
481
|
+
# :health and :postprocessing work without authentication: they do not use api_v5.
|
|
487
482
|
command :health, description: 'Check Faspex 5 health'
|
|
488
|
-
command :version, description: 'Show Faspex 5 version',
|
|
489
|
-
command :bearer_token, description: 'Show OAuth bearer token',
|
|
490
|
-
|
|
483
|
+
command :version, description: 'Show Faspex 5 version', action: ->(**) { Result::SingleObject.new(api_v5.read('version')) }
|
|
484
|
+
command :bearer_token, description: 'Show OAuth bearer token', action: ->(**) { Result::Text.new(api_v5.oauth.authorization) }
|
|
485
|
+
# Package id argument; with a public link to a package, setup_package_id provides it instead
|
|
486
|
+
PACKAGE_ID_ARG = [{name: :package_id, type: :identifier}].freeze
|
|
487
|
+
private_constant :PACKAGE_ID_ARG
|
|
488
|
+
command :packages, description: 'Manage packages'
|
|
491
489
|
commands_under :packages do
|
|
492
490
|
command :list, description: 'List packages',
|
|
493
491
|
arguments: [{name: :filter, mandatory: false, default: nil, type: Proc}]
|
|
494
492
|
command :send, description: 'Send a package', transfer_paths: :send,
|
|
495
|
-
arguments: [{name: :
|
|
496
|
-
action: ->(
|
|
497
|
-
command :show, description: 'Show a package', setup: :setup_package_id,
|
|
498
|
-
action: ->(package_id:, **) { Result::SingleObject.new(
|
|
493
|
+
arguments: [{name: :package, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::FASPEX, 'packages.post')}],
|
|
494
|
+
action: ->(package:, **) { package_send(package) }
|
|
495
|
+
command :show, description: 'Show a package', setup: :setup_package_id, arguments: PACKAGE_ID_ARG,
|
|
496
|
+
action: ->(package_id:, **) { Result::SingleObject.new(api_v5.read("packages/#{package_id}")) }
|
|
499
497
|
command :browse, description: 'Browse package files', setup: :setup_package_id,
|
|
500
|
-
arguments: [{name: :folder_path,
|
|
498
|
+
arguments: PACKAGE_ID_ARG + [{name: :folder_path, mandatory: false, default: '/'}],
|
|
501
499
|
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
500
|
command :status, description: 'Wait for package status', setup: :setup_package_id,
|
|
503
|
-
arguments: [{name: :status_list, type: Array, mandatory: false, default: nil}],
|
|
501
|
+
arguments: PACKAGE_ID_ARG + [{name: :status_list, type: Array, mandatory: false, default: nil}],
|
|
504
502
|
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
|
|
506
|
-
command :receive, description: 'Receive a package', setup: :setup_package_id, transfer_paths: :receive,
|
|
503
|
+
command :delete, description: 'Delete packages', setup: :setup_package_id, arguments: PACKAGE_ID_ARG
|
|
504
|
+
command :receive, description: 'Receive a package', setup: :setup_package_id, transfer_paths: :receive, arguments: PACKAGE_ID_ARG,
|
|
507
505
|
action: ->(package_id:, **) { package_receive(package_id) }
|
|
508
|
-
command(:file_processing, description: 'Show file processing status', setup: :setup_package_id, action: lambda do |package_id:, **|
|
|
509
|
-
result, count =
|
|
506
|
+
command(:file_processing, description: 'Show file processing status', setup: :setup_package_id, arguments: PACKAGE_ID_ARG, action: lambda do |package_id:, **|
|
|
507
|
+
result, count = api_v5.list_entities_limit_offset_total_count(entity: "packages/#{package_id}/file_statuses", items_key: 'files')
|
|
510
508
|
Result::ObjectList.new(result, total: count)
|
|
511
509
|
end)
|
|
512
510
|
end
|
|
513
|
-
command :admin, description: 'Administer Faspex 5'
|
|
514
|
-
command :user, description: 'Manage current user'
|
|
515
|
-
command :shared_folders, description: 'Browse shared folders'
|
|
516
|
-
command :gateway, description: 'Start Faspex 4 gateway emulation',
|
|
511
|
+
command :admin, description: 'Administer Faspex 5'
|
|
512
|
+
command :user, description: 'Manage current user'
|
|
513
|
+
command :shared_folders, description: 'Browse shared folders'
|
|
514
|
+
command :gateway, description: 'Start Faspex 4 gateway emulation',
|
|
517
515
|
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}}]
|
|
518
516
|
command :postprocessing, description: 'Start Faspex 4 post-processing server',
|
|
519
517
|
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}}]
|
|
520
|
-
command :invitations, description: 'Manage invitations'
|
|
518
|
+
command :invitations, description: 'Manage invitations'
|
|
521
519
|
|
|
522
520
|
commands_under :invitations do
|
|
523
521
|
command :create, description: 'Create an invitation',
|
|
524
|
-
arguments: [{name: :
|
|
525
|
-
command
|
|
526
|
-
|
|
522
|
+
arguments: [{name: :invitation, type: Hash, bulk: true}]
|
|
523
|
+
command(
|
|
524
|
+
:resend, description: 'Resend an invitation',
|
|
525
|
+
arguments: [{name: :invitation_id, type: :identifier}],
|
|
526
|
+
action: lambda do |invitation_id:, **|
|
|
527
|
+
api_v5.create("invitations/#{invitation_id}/resend", nil)
|
|
528
|
+
Result::Status.new('Invitation resent')
|
|
529
|
+
end
|
|
530
|
+
)
|
|
527
531
|
crud_commands entity: 'invitations',
|
|
528
|
-
api:
|
|
532
|
+
api: :api_v5,
|
|
529
533
|
operations: Operations::ALL - %i[create],
|
|
530
534
|
items_key: 'invitations',
|
|
531
535
|
display_fields: %w[id public recipient_type recipient_name email_address]
|
|
532
536
|
end
|
|
533
537
|
|
|
534
538
|
commands_under :user do
|
|
535
|
-
command :account, description: 'Show account information', action: -> { Result::SingleObject.new(
|
|
539
|
+
command :account, description: 'Show account information', action: ->(**) { Result::SingleObject.new(api_v5.read('account', query_read_delete)) }
|
|
536
540
|
command :profile, description: 'Manage user profile'
|
|
537
541
|
end
|
|
538
542
|
|
|
539
543
|
commands_under %i[user profile] do
|
|
540
|
-
command :show, description: 'Show user profile', action: -> { Result::SingleObject.new(
|
|
544
|
+
command :show, description: 'Show user profile', action: ->(**) { Result::SingleObject.new(api_v5.read('account/preferences')) }
|
|
541
545
|
command(
|
|
542
546
|
:modify,
|
|
543
547
|
description: 'Modify user profile',
|
|
544
|
-
arguments: [{name: :
|
|
545
|
-
action: lambda do |
|
|
546
|
-
|
|
548
|
+
arguments: [{name: :profile, type: Hash}],
|
|
549
|
+
action: lambda do |profile:, **|
|
|
550
|
+
api_v5.update('account/preferences', profile)
|
|
547
551
|
Result::Status.new('modified')
|
|
548
552
|
end
|
|
549
553
|
)
|
|
550
554
|
end
|
|
551
555
|
|
|
552
556
|
commands_under :shared_folders do
|
|
553
|
-
command :list, description: 'List shared folders', action: -> { Result::ObjectList.new(
|
|
557
|
+
command :list, description: 'List shared folders', action: ->(**) { Result::ObjectList.new(api_v5.read('shared_folders')['shared_folders']) }
|
|
554
558
|
command :browse, description: 'Browse a shared folder',
|
|
555
559
|
arguments: [{name: :shared_folder_id, type: :identifier, lookup: :lookup_shared_folder_id},
|
|
556
|
-
{name: :folder_path,
|
|
560
|
+
{name: :folder_path, mandatory: false, default: '/'}]
|
|
557
561
|
end
|
|
558
562
|
|
|
559
563
|
# admin sub-tree: fixed commands + all ADMIN_RESOURCES with their sub-commands
|
|
@@ -561,21 +565,26 @@ module Aspera
|
|
|
561
565
|
command :configuration, description: 'Manage Faspex 5 configuration'
|
|
562
566
|
command :smtp, description: 'Manage SMTP configuration'
|
|
563
567
|
command :events, description: 'List events'
|
|
564
|
-
command
|
|
565
|
-
|
|
568
|
+
command(
|
|
569
|
+
:clean_deleted, description: 'Clean deleted packages',
|
|
570
|
+
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}}],
|
|
571
|
+
action: lambda do |parameters: {}, **|
|
|
572
|
+
parameters = api_v5.read('configuration').slice('days_before_deleting_package_records') if parameters.empty?
|
|
573
|
+
Result::SingleObject.new(api_v5.create('internal/packages/clean_deleted', parameters))
|
|
574
|
+
end
|
|
575
|
+
)
|
|
566
576
|
Api::Faspex::ADMIN_RESOURCES.each do |res|
|
|
567
577
|
cfg = RESOURCE_CONFIG.fetch(res, {})
|
|
568
|
-
extra = cfg[:extra_commands] ||
|
|
569
|
-
ia_cmds = cfg[:instance_arg_commands] || {}
|
|
578
|
+
extra = cfg[:extra_commands] || {}
|
|
570
579
|
is_singleton = cfg[:is_singleton] || false
|
|
571
580
|
entity_path = cfg[:entity] || res.to_s
|
|
572
581
|
crud_ops = ((cfg[:commands] || Operations::ALL) - %i[list]) & Operations::ALL
|
|
573
582
|
|
|
574
|
-
command res, description: "Manage #{res
|
|
575
|
-
commands_under
|
|
583
|
+
command res, description: "Manage #{entity_noun(res, singular: false)}"
|
|
584
|
+
commands_under res do
|
|
576
585
|
# List is handled with Faspex 5 pagination (item_list_with_total)
|
|
577
586
|
unless is_singleton
|
|
578
|
-
list_kwargs = {description:
|
|
587
|
+
list_kwargs = {description: operation_description(:list, entity_noun(entity_path))}
|
|
579
588
|
list_kwargs[:query_schema] = Schema::Registry.query_params(cfg[:query_component], entity_path) if cfg[:query_component]
|
|
580
589
|
command :list, **list_kwargs
|
|
581
590
|
end
|
|
@@ -594,9 +603,8 @@ module Aspera
|
|
|
594
603
|
)
|
|
595
604
|
|
|
596
605
|
# Extra commands (e.g. browse, reset_password, next)
|
|
597
|
-
extra.each do |
|
|
598
|
-
|
|
599
|
-
command c, description: c.to_s.tr('_', ' ').capitalize, **ia
|
|
606
|
+
extra.each do |name, attrs|
|
|
607
|
+
command name, **attrs
|
|
600
608
|
end
|
|
601
609
|
end
|
|
602
610
|
end
|
|
@@ -612,19 +620,19 @@ module Aspera
|
|
|
612
620
|
# entity: :sf_entity is resolved at runtime from ctx (injected by setup_admin_nodes_shared_folders).
|
|
613
621
|
commands_under %i[admin nodes shared_folders] do
|
|
614
622
|
crud_commands entity: :sf_entity,
|
|
615
|
-
api:
|
|
623
|
+
api: :api_v5,
|
|
616
624
|
name: 'shared folder',
|
|
617
625
|
lookup: :lookup_sf_id,
|
|
618
626
|
items_key: 'shared_folders'
|
|
619
|
-
command :user, description: '
|
|
620
|
-
arguments: [{name: :
|
|
627
|
+
command :user, description: 'Manage custom access users',
|
|
628
|
+
arguments: [{name: :shared_folder_id, type: :identifier, lookup: :lookup_sf_id}],
|
|
621
629
|
setup: :setup_admin_nodes_shared_folders_user
|
|
622
630
|
end
|
|
623
631
|
|
|
624
632
|
# admin > nodes > shared_folders > user sub-tree (custom access users)
|
|
625
633
|
# entity: :user_path is resolved at runtime from ctx (injected by setup_admin_nodes_shared_folders_user).
|
|
626
634
|
commands_under %i[admin nodes shared_folders user] do
|
|
627
|
-
crud_commands entity: :user_path, api:
|
|
635
|
+
crud_commands entity: :user_path, api: :api_v5, name: 'custom access user', lookup: :lookup_sf_user_id, items_key: 'users'
|
|
628
636
|
end
|
|
629
637
|
|
|
630
638
|
# `members` and `saml_groups`
|
|
@@ -632,41 +640,48 @@ module Aspera
|
|
|
632
640
|
CRUD_NO_LIST = %i[create modify delete show].freeze
|
|
633
641
|
|
|
634
642
|
RES_SINGULAR = {shared_inboxes: :shared_inbox, workgroups: :workgroup}.freeze
|
|
635
|
-
|
|
643
|
+
# Access levels of members, per resource
|
|
644
|
+
MEMBER_ACCESS = {
|
|
645
|
+
shared_inboxes: %i[submit_only standard shared_inbox_admin].freeze,
|
|
646
|
+
workgroups: %i[standard workgroup_admin].freeze
|
|
647
|
+
}.freeze
|
|
648
|
+
private_constant :RES_SINGULAR, :MEMBER_ACCESS
|
|
636
649
|
|
|
637
650
|
# admin > shared_inboxes|workgroups > members|saml_groups|invite_external_collaborator:
|
|
638
651
|
# res_id consumed via arguments:(:identifier) + lookup:, builds res_instance_path for all children
|
|
639
652
|
%i[shared_inboxes workgroups].each do |res|
|
|
640
|
-
lookup_res_id = ->(field, value, **) {
|
|
653
|
+
lookup_res_id = ->(field, value, **) { api_v5.lookup_entity_by_field(entity: res.to_s, field: field, value: value, query: {'all': true})['id'] }
|
|
641
654
|
commands_under [:admin, res] do
|
|
642
|
-
command :members, description: '
|
|
655
|
+
command :members, description: 'Manage members',
|
|
643
656
|
arguments: [{name: :"#{RES_SINGULAR[res]}_id", type: :identifier, lookup: lookup_res_id}],
|
|
644
657
|
setup: :"setup_admin_#{res}_instance"
|
|
645
|
-
command :saml_groups, description: '
|
|
658
|
+
command :saml_groups, description: 'Manage SAML groups',
|
|
646
659
|
arguments: [{name: :"#{RES_SINGULAR[res]}_id", type: :identifier, lookup: lookup_res_id}],
|
|
647
660
|
setup: :"setup_admin_#{res}_instance"
|
|
648
661
|
command :invite_external_collaborator, description: 'Invite external collaborator',
|
|
649
662
|
arguments: [{name: :"#{RES_SINGULAR[res]}_id", type: :identifier, lookup: lookup_res_id},
|
|
650
|
-
{name: :
|
|
663
|
+
{name: :collaborator, type: Hash}]
|
|
651
664
|
end
|
|
652
665
|
|
|
653
666
|
commands_under [:admin, res, :members] do
|
|
654
667
|
CRUD_NO_SHOW.each do |c|
|
|
655
668
|
args =
|
|
656
669
|
if c.eql?(:create)
|
|
657
|
-
{arguments: [{name: :users, bulk: true}, {name: :access, mandatory: false, default: :standard}]}
|
|
670
|
+
{arguments: [{name: :users, bulk: true}, {name: :access, allowed: MEMBER_ACCESS[res], mandatory: false, default: :standard}]}
|
|
671
|
+
elsif c.eql?(:modify)
|
|
672
|
+
{arguments: [{name: :member_id, type: :identifier, lookup: :"lookup_#{res}_members_id"}, {name: :member, type: Hash}]}
|
|
658
673
|
elsif Operations::INSTANCE.include?(c)
|
|
659
674
|
{arguments: [{name: :member_id, type: :identifier, lookup: :"lookup_#{res}_members_id"}]}
|
|
660
675
|
else
|
|
661
676
|
{}
|
|
662
677
|
end
|
|
663
|
-
command c, description: c
|
|
678
|
+
command c, description: operation_description(c, 'member'), **args
|
|
664
679
|
end
|
|
665
680
|
end
|
|
666
681
|
|
|
667
682
|
commands_under [:admin, res, :saml_groups] do
|
|
668
683
|
crud_commands entity: :saml_groups_path,
|
|
669
|
-
api:
|
|
684
|
+
api: :api_v5,
|
|
670
685
|
name: 'SAML group',
|
|
671
686
|
operations: CRUD_NO_SHOW,
|
|
672
687
|
lookup: :"lookup_#{res}_saml_groups_id",
|
|
@@ -675,57 +690,51 @@ module Aspera
|
|
|
675
690
|
end
|
|
676
691
|
|
|
677
692
|
commands_under %i[admin configuration] do
|
|
678
|
-
command :show, description: 'Show configuration', action: -> { Result::SingleObject.new(
|
|
693
|
+
command :show, description: 'Show configuration', action: ->(**) { Result::SingleObject.new(api_v5.read('configuration')) }
|
|
679
694
|
command :modify, description: 'Modify configuration',
|
|
680
|
-
arguments: [{name: :
|
|
681
|
-
action: ->(
|
|
695
|
+
arguments: [{name: :configuration, type: Hash}],
|
|
696
|
+
action: ->(configuration:, **) { Result::SingleObject.new(api_v5.update('configuration', configuration)) }
|
|
682
697
|
end
|
|
683
698
|
|
|
684
699
|
commands_under %i[admin smtp] do
|
|
685
|
-
command :show, description: 'Show SMTP configuration', action: -> { Result::SingleObject.new(
|
|
700
|
+
command :show, description: 'Show SMTP configuration', action: ->(**) { Result::SingleObject.new(api_v5.read('configuration/smtp')) }
|
|
686
701
|
command :create, description: 'Create SMTP configuration',
|
|
687
|
-
arguments: [{name: :
|
|
688
|
-
action: ->(
|
|
702
|
+
arguments: [{name: :smtp, type: Hash}],
|
|
703
|
+
action: ->(smtp:, **) { Result::SingleObject.new(api_v5.create('configuration/smtp', smtp)) }
|
|
689
704
|
command :modify, description: 'Modify SMTP configuration',
|
|
690
|
-
arguments: [{name: :
|
|
691
|
-
action: ->(
|
|
705
|
+
arguments: [{name: :smtp, type: Hash}],
|
|
706
|
+
action: ->(smtp:, **) { Result::SingleObject.new(api_v5.update('configuration/smtp', smtp)) }
|
|
692
707
|
command(
|
|
693
708
|
:delete, description: 'Delete SMTP configuration',
|
|
694
|
-
action: lambda do
|
|
695
|
-
|
|
709
|
+
action: lambda do |**|
|
|
710
|
+
api_v5.delete('configuration/smtp')
|
|
696
711
|
Result::Status.new('SMTP configuration deleted')
|
|
697
712
|
end
|
|
698
713
|
)
|
|
699
714
|
command :test, description: 'Test SMTP configuration',
|
|
700
|
-
arguments: [{name: :
|
|
715
|
+
arguments: [{name: :recipient}]
|
|
701
716
|
end
|
|
702
717
|
|
|
703
718
|
commands_under %i[admin events] do
|
|
704
719
|
command(
|
|
705
720
|
:application, description: 'List application events',
|
|
706
|
-
action: lambda do
|
|
707
|
-
list, total =
|
|
721
|
+
action: lambda do |**|
|
|
722
|
+
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
723
|
Result::ObjectList.new(list, total: total, fields: %w[event_type created_at application user.name])
|
|
709
724
|
end
|
|
710
725
|
)
|
|
711
726
|
command(
|
|
712
727
|
:webhook, description: 'List webhook events',
|
|
713
|
-
action: lambda do
|
|
714
|
-
list, total =
|
|
728
|
+
action: lambda do |**|
|
|
729
|
+
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
730
|
Result::ObjectList.new(list, total: total)
|
|
716
731
|
end
|
|
717
732
|
)
|
|
718
733
|
end
|
|
719
734
|
|
|
720
|
-
# admin > clean_deleted handler (leaf, no sub-commands)
|
|
721
|
-
define_action_method(%i[admin clean_deleted]) do |input_data: {}, **|
|
|
722
|
-
input_data = @api_v5.read('configuration').slice('days_before_deleting_package_records') if input_data.empty?
|
|
723
|
-
Result::SingleObject.new(@api_v5.create('internal/packages/clean_deleted', input_data))
|
|
724
|
-
end
|
|
725
|
-
|
|
726
735
|
# admin > <resource> > list
|
|
727
736
|
Api::Faspex::ADMIN_RESOURCES.each do |res|
|
|
728
|
-
define_action_method([:admin, res, :list]) do
|
|
737
|
+
define_action_method([:admin, res, :list]) do |**|
|
|
729
738
|
args = res_exec_args(res)
|
|
730
739
|
# Special case: email_notifications list returns a fixed value list
|
|
731
740
|
next Result::ValueList.new(Api::Faspex::EMAIL_NOTIF_LIST, name: 'email_id') if res.eql?(:email_notifications)
|
|
@@ -740,9 +749,9 @@ module Aspera
|
|
|
740
749
|
end
|
|
741
750
|
end
|
|
742
751
|
|
|
743
|
-
def action_admin_smtp_test(
|
|
744
|
-
|
|
745
|
-
creation =
|
|
752
|
+
def action_admin_smtp_test(recipient:, **)
|
|
753
|
+
recipient = {test_email_recipient: recipient} if recipient.is_a?(String)
|
|
754
|
+
creation = api_v5.create('configuration/smtp/test', recipient)
|
|
746
755
|
result = wait_for_job(creation['job_id'])
|
|
747
756
|
begin
|
|
748
757
|
result['serialized_args'] = JSON.parse(result['serialized_args'])
|
|
@@ -753,15 +762,15 @@ module Aspera
|
|
|
753
762
|
end
|
|
754
763
|
|
|
755
764
|
# admin > accounts > reset_password
|
|
756
|
-
def action_admin_accounts_reset_password(
|
|
757
|
-
|
|
765
|
+
def action_admin_accounts_reset_password(account_id:, **)
|
|
766
|
+
api_v5.create("accounts/#{account_id}/reset_password", {})
|
|
758
767
|
Result::Status.new('password reset, user shall check email')
|
|
759
768
|
end
|
|
760
769
|
|
|
761
770
|
# admin > file_processing > next
|
|
762
|
-
def action_admin_file_processing_next
|
|
771
|
+
def action_admin_file_processing_next(**)
|
|
763
772
|
args = res_exec_args(:file_processing)
|
|
764
|
-
result, count =
|
|
773
|
+
result, count = api_v5.list_entities_limit_offset_total_count(entity: args[:entity], operation: 'POST', items_key: 'files')
|
|
765
774
|
Result::ObjectList.new(result, total: count)
|
|
766
775
|
end
|
|
767
776
|
|
|
@@ -778,18 +787,18 @@ module Aspera
|
|
|
778
787
|
# Lookup shared folder id by field/value within a node's shared_folders entity.
|
|
779
788
|
# sf_entity is in ctx from setup_admin_nodes_shared_folders (Phase A of parent).
|
|
780
789
|
def lookup_sf_id(field, value, sf_entity:, **)
|
|
781
|
-
|
|
790
|
+
api_v5.lookup_entity_by_field(entity: sf_entity, items_key: 'shared_folders', field: field, value: value)['id']
|
|
782
791
|
end
|
|
783
792
|
|
|
784
793
|
# Lookup custom access user id by field/value within a shared folder's users entity.
|
|
785
794
|
# user_path is in ctx from setup_admin_nodes_shared_folders_user (Phase A of parent).
|
|
786
795
|
def lookup_sf_user_id(field, value, user_path:, **)
|
|
787
|
-
|
|
796
|
+
api_v5.lookup_entity_by_field(entity: user_path, items_key: 'users', field: field, value: value)['id']
|
|
788
797
|
end
|
|
789
798
|
|
|
790
|
-
# admin > nodes > shared_folders > user —
|
|
791
|
-
def setup_admin_nodes_shared_folders_user(sf_entity:,
|
|
792
|
-
{user_path: "#{sf_entity}/#{
|
|
799
|
+
# admin > nodes > shared_folders > user — shared_folder_id: already in ctx via arguments: on the :user command
|
|
800
|
+
def setup_admin_nodes_shared_folders_user(sf_entity:, shared_folder_id:, **)
|
|
801
|
+
{user_path: "#{sf_entity}/#{shared_folder_id}/custom_access_users"}
|
|
793
802
|
end
|
|
794
803
|
|
|
795
804
|
# admin > shared_inboxes|workgroups — res_id: already in ctx via arguments: on the :members|:saml_groups command
|
|
@@ -810,7 +819,7 @@ module Aspera
|
|
|
810
819
|
users = [users] unless users.is_a?(Array)
|
|
811
820
|
users.map do |user|
|
|
812
821
|
if (m = Parser.percent_selector(user))
|
|
813
|
-
|
|
822
|
+
api_v5.lookup_entity_by_field(entity: 'accounts', field: m[:field], value: m[:value], query: Rest.php_style({type: ACCOUNT_TYPES}))['id']
|
|
814
823
|
else
|
|
815
824
|
user
|
|
816
825
|
end
|
|
@@ -822,11 +831,11 @@ module Aspera
|
|
|
822
831
|
%i[shared_inboxes workgroups].each do |res|
|
|
823
832
|
define_method(:"lookup_#{res}_members_id") do |field, value, res_instance_path:, **|
|
|
824
833
|
res_path = "#{res_instance_path}/members"
|
|
825
|
-
|
|
834
|
+
api_v5.lookup_entity_by_field(entity: res_path, field: field, value: value, query: Rest.php_style({type: %w[user]}))['user_id']
|
|
826
835
|
end
|
|
827
836
|
define_method(:"lookup_#{res}_saml_groups_id") do |field, value, res_instance_path:, **|
|
|
828
837
|
res_path = "#{res_instance_path}/saml_groups"
|
|
829
|
-
|
|
838
|
+
api_v5.lookup_entity_by_field(entity: res_path, field: field, value: value, query: Rest.php_style({type: %w[user]}))['user_id']
|
|
830
839
|
end
|
|
831
840
|
end
|
|
832
841
|
|
|
@@ -834,52 +843,52 @@ module Aspera
|
|
|
834
843
|
# (saml_groups CRUD is handled by crud_commands)
|
|
835
844
|
%i[shared_inboxes workgroups].each do |res|
|
|
836
845
|
define_action_method([:admin, res, :members, :list]) do |res_instance_path:, **|
|
|
837
|
-
entity_list(api:
|
|
846
|
+
entity_list(api: api_v5, entity: "#{res_instance_path}/members", items_key: 'members')
|
|
838
847
|
end
|
|
839
848
|
|
|
840
|
-
define_action_method([:admin, res, :members, :modify]) do |res_instance_path:,
|
|
841
|
-
entity_modify(api:
|
|
849
|
+
define_action_method([:admin, res, :members, :modify]) do |res_instance_path:, member_id:, member:, **|
|
|
850
|
+
entity_modify(api: api_v5, entity: "#{res_instance_path}/members", id: member_id, data: member)
|
|
842
851
|
end
|
|
843
852
|
|
|
844
853
|
define_action_method([:admin, res, :members, :delete]) do |res_instance_path:, **kwargs|
|
|
845
|
-
entity_delete(api:
|
|
854
|
+
entity_delete(api: api_v5, entity: "#{res_instance_path}/members", id: kwargs[:member_id])
|
|
846
855
|
end
|
|
847
856
|
|
|
848
857
|
define_action_method([:admin, res, :members, :create]) do |users:, access:, res_instance_path:, **|
|
|
849
858
|
res_path = "#{res_instance_path}/members"
|
|
850
859
|
resolved = resolve_member_user_ids(users)
|
|
851
|
-
|
|
852
|
-
entity_create(api: @api_v5, entity: res_path, input_data: input_data)
|
|
860
|
+
entity_create(api: api_v5, entity: res_path, data: {user: resolved.map { |u| {id: u, access: access} }})
|
|
853
861
|
end
|
|
854
862
|
end
|
|
855
863
|
|
|
856
864
|
# admin > shared_inboxes|workgroups > invite_external_collaborator
|
|
857
865
|
%i[shared_inboxes workgroups].each do |res|
|
|
858
|
-
define_action_method([:admin, res, :invite_external_collaborator]) do |
|
|
866
|
+
define_action_method([:admin, res, :invite_external_collaborator]) do |collaborator:, **kwargs|
|
|
859
867
|
res_instance_path = "#{res}/#{kwargs[:"#{RES_SINGULAR[res]}_id"]}"
|
|
860
|
-
result =
|
|
868
|
+
result = api_v5.create("#{res_instance_path}/external_collaborator", collaborator)
|
|
861
869
|
formatter.display_status(result['message'])
|
|
862
|
-
Result::SingleObject.new(
|
|
870
|
+
Result::SingleObject.new(api_v5.lookup_entity_by_field(entity: "#{res_instance_path}/members", items_key: 'members', value: collaborator['email_address'], query: {}))
|
|
863
871
|
end
|
|
864
872
|
end
|
|
865
873
|
|
|
866
|
-
# ---
|
|
874
|
+
# --- API ---
|
|
867
875
|
|
|
868
|
-
#
|
|
869
|
-
# @return [
|
|
870
|
-
def
|
|
871
|
-
return
|
|
876
|
+
# Faspex 5 API, built from CLI options on first use.
|
|
877
|
+
# @return [Api::Faspex]
|
|
878
|
+
def api_v5
|
|
879
|
+
return @api_v5 if @api_v5
|
|
872
880
|
@api_v5 = Api::Faspex.new(**Oauth.kwargs_from_options(options))
|
|
873
881
|
# in case user wants to use HTTPGW tell transfer agent how to get address
|
|
874
882
|
transfer.httpgw_url_cb = lambda { @api_v5.read('account')['gateway_url'] }
|
|
875
|
-
|
|
883
|
+
@api_v5
|
|
876
884
|
end
|
|
877
885
|
|
|
878
|
-
# Setup for package sub-commands that need an id:
|
|
879
|
-
#
|
|
886
|
+
# Setup for package sub-commands that need an id: with a public link to a package, the id comes from the link.
|
|
887
|
+
# Leaf setup runs before argument resolution: the declared package_id argument is then not read.
|
|
888
|
+
# @return [Hash] ctx key: package_id, or empty (package_id is read from the command line)
|
|
880
889
|
def setup_package_id(**)
|
|
881
|
-
|
|
882
|
-
{package_id: package_id}
|
|
890
|
+
return {} unless api_v5.pub_link_context&.key?('package_id')
|
|
891
|
+
{package_id: api_v5.pub_link_context['package_id']}
|
|
883
892
|
end
|
|
884
893
|
|
|
885
894
|
def action_packages_list(filter: nil, **)
|
|
@@ -895,7 +904,7 @@ module Aspera
|
|
|
895
904
|
ids = package_id.is_a?(Array) ? package_id : [package_id]
|
|
896
905
|
Aspera.assert_array_all(ids, String) { 'Package id(s)' }
|
|
897
906
|
# API returns 204, empty on success
|
|
898
|
-
|
|
907
|
+
api_v5.call(
|
|
899
908
|
operation: 'DELETE',
|
|
900
909
|
subpath: 'packages',
|
|
901
910
|
content_type: Mime::JSON,
|
|
@@ -907,10 +916,10 @@ module Aspera
|
|
|
907
916
|
|
|
908
917
|
# --- handlers ---
|
|
909
918
|
|
|
910
|
-
def action_health
|
|
919
|
+
def action_health(**)
|
|
911
920
|
nagios = Nagios.new
|
|
912
921
|
begin
|
|
913
|
-
data, http = Rest.new(base_url: options.get_option(:url, mandatory: true))
|
|
922
|
+
data, http = Rest::Client.new(base_url: options.get_option(:url, mandatory: true))
|
|
914
923
|
.read('health', ret: :both)
|
|
915
924
|
data.each do |k, v|
|
|
916
925
|
nagios.add_ok(k, v.to_s)
|
|
@@ -925,7 +934,7 @@ module Aspera
|
|
|
925
934
|
# Lookup a shared folder id by field/value.
|
|
926
935
|
# Called via lookup: :lookup_shared_folder_id on the shared_folders > browse command.
|
|
927
936
|
def lookup_shared_folder_id(field, value, **)
|
|
928
|
-
all =
|
|
937
|
+
all = api_v5.read('shared_folders')['shared_folders']
|
|
929
938
|
matches = all.select { |i| i[field].eql?(value) }
|
|
930
939
|
Aspera.assert(!matches.empty?) { "no match for #{field} = #{value}" }
|
|
931
940
|
Aspera.assert(matches.length == 1) { "multiple matches for #{field} = #{value}" }
|
|
@@ -933,7 +942,7 @@ module Aspera
|
|
|
933
942
|
end
|
|
934
943
|
|
|
935
944
|
def action_shared_folders_browse(folder_path:, shared_folder_id:, **)
|
|
936
|
-
all_shared_folders =
|
|
945
|
+
all_shared_folders = api_v5.read('shared_folders')['shared_folders']
|
|
937
946
|
node = all_shared_folders.find { |i| i['id'].eql?(shared_folder_id) }
|
|
938
947
|
Aspera.assert(!node.nil?) { "No such shared folder id #{shared_folder_id}" }
|
|
939
948
|
browse_folder("nodes/#{node['node_id']}/shared_folders/#{shared_folder_id}/browse", {}, folder_path: folder_path)
|
|
@@ -941,15 +950,10 @@ module Aspera
|
|
|
941
950
|
|
|
942
951
|
# invitations sub-handlers
|
|
943
952
|
|
|
944
|
-
def
|
|
945
|
-
|
|
946
|
-
Result::Status.new('Invitation resent')
|
|
947
|
-
end
|
|
948
|
-
|
|
949
|
-
def action_invitations_create(input_data:, **)
|
|
950
|
-
bulk_result(input_data, command: :create) do |params|
|
|
953
|
+
def action_invitations_create(invitation:, **)
|
|
954
|
+
bulk_result(invitation, command: :create) do |params|
|
|
951
955
|
endpoint = params.key?('recipient_name') ? 'public_invitations' : 'invitations'
|
|
952
|
-
|
|
956
|
+
api_v5.create(endpoint, params)
|
|
953
957
|
end
|
|
954
958
|
end
|
|
955
959
|
|
|
@@ -959,7 +963,7 @@ module Aspera
|
|
|
959
963
|
uri = URI.parse(parameters.delete(:url) { WebServerSimple::DEFAULT_URL })
|
|
960
964
|
server = WebServerSimple.new(uri, **parameters.slice(*WebServerSimple::PARAMS))
|
|
961
965
|
Aspera.assert(parameters.except(*WebServerSimple::PARAMS).empty?) { "unexpected parameters: #{parameters.except(*WebServerSimple::PARAMS).keys}" }
|
|
962
|
-
server.mount(uri.path, Faspex4GWServlet,
|
|
966
|
+
server.mount(uri.path, Faspex4GWServlet, api_v5, nil)
|
|
963
967
|
server.start
|
|
964
968
|
Result::Status.new('Gateway terminated')
|
|
965
969
|
end
|
|
@@ -974,12 +978,11 @@ module Aspera
|
|
|
974
978
|
server.start
|
|
975
979
|
Result::Status.new('Gateway terminated')
|
|
976
980
|
end
|
|
977
|
-
SHARED_INBOX_MEMBER_LEVELS = %i[submit_only standard shared_inbox_admin].freeze
|
|
978
981
|
ACCOUNT_TYPES = %w{local_user saml_user self_registered_user external_user}.freeze
|
|
979
982
|
WORKGROUP_TYPES = %w{workgroup shared_inbox}.freeze
|
|
980
983
|
CONTACT_TYPES = (WORKGROUP_TYPES + %w{distribution_list user external_user}).freeze
|
|
981
984
|
PACKAGE_RECIPIENT_TYPES = %i{recipients private_recipients notified_on_upload notified_on_download notified_on_receipt}
|
|
982
|
-
private_constant :
|
|
985
|
+
private_constant :ACCOUNT_TYPES, :CONTACT_TYPES, :PACKAGE_RECIPIENT_TYPES,
|
|
983
986
|
:CRUD_NO_SHOW, :CRUD_NO_LIST
|
|
984
987
|
end
|
|
985
988
|
end
|