aspera-cli 4.27.2 → 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 +50 -0
- data/bin/ascli +2 -1
- data/docs/README.md +804 -746
- 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 +430 -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/coverage.rb +1 -0
- data/lib/aspera/environment.rb +6 -0
- 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 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/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
|
@@ -18,11 +18,13 @@ require 'aspera/assert'
|
|
|
18
18
|
require 'aspera/graphql'
|
|
19
19
|
require 'securerandom'
|
|
20
20
|
require 'date'
|
|
21
|
+
require 'aspera/rainbow'
|
|
22
|
+
using Rainbow
|
|
21
23
|
|
|
22
24
|
module Aspera
|
|
23
25
|
module Cli
|
|
24
26
|
module Plugins
|
|
25
|
-
class Aoc < Oauth
|
|
27
|
+
class Aoc < Oauth # rubocop:disable Metrics/ClassLength
|
|
26
28
|
# default redirect for AoC web auth
|
|
27
29
|
REDIRECT_LOCALHOST = 'http://localhost:12345'
|
|
28
30
|
# admin objects that can be manipulated
|
|
@@ -70,7 +72,7 @@ module Aspera
|
|
|
70
72
|
base_url = "#{base_url}.#{Api::AoC::SAAS_DOMAIN_PROD}" unless base_url.include?('.')
|
|
71
73
|
# AoC is only https
|
|
72
74
|
return unless base_url.start_with?('https://')
|
|
73
|
-
location = Rest.new(base_url: base_url, redirect_max: 0).call(operation: 'GET', subpath: 'auth/ping', exception: false, ret: :resp)['Location']
|
|
75
|
+
location = Rest::Client.new(base_url: base_url, redirect_max: 0).call(operation: 'GET', subpath: 'auth/ping', exception: false, ret: :resp)['Location']
|
|
74
76
|
return if location.nil?
|
|
75
77
|
redirect_uri = URI.parse(location)
|
|
76
78
|
od = Api::AoC.split_org_domain(URI.parse(base_url))
|
|
@@ -145,25 +147,25 @@ module Aspera
|
|
|
145
147
|
def register_short_link_commands(base, parent_path)
|
|
146
148
|
base.commands_under(parent_path) do
|
|
147
149
|
base.command(
|
|
148
|
-
:create, description: '
|
|
149
|
-
arguments: [{name: :
|
|
150
|
+
:create, description: base.operation_description(:create, 'short link'),
|
|
151
|
+
arguments: [{name: :short_link, type: Hash, mandatory: false, default: {}}]
|
|
150
152
|
)
|
|
151
153
|
base.command(
|
|
152
|
-
:modify, description: '
|
|
153
|
-
arguments: [{name: :short_link_id, type: :identifier}, {name: :
|
|
154
|
+
:modify, description: base.operation_description(:modify, 'short link'),
|
|
155
|
+
arguments: [{name: :short_link_id, type: :identifier}, {name: :short_link, type: Hash, mandatory: false, default: {}}]
|
|
154
156
|
)
|
|
155
|
-
base.command(:list, description: '
|
|
157
|
+
base.command(:list, description: base.operation_description(:list, 'short link'))
|
|
156
158
|
base.command(
|
|
157
|
-
:show, description: '
|
|
159
|
+
:show, description: base.operation_description(:show, 'short link'),
|
|
158
160
|
arguments: [{name: :short_link_id, type: :identifier}]
|
|
159
161
|
)
|
|
160
162
|
base.command(
|
|
161
|
-
:delete, description: '
|
|
163
|
+
:delete, description: base.operation_description(:delete, 'short link'),
|
|
162
164
|
arguments: [{name: :short_link_id, type: :identifier}]
|
|
163
165
|
)
|
|
164
166
|
end
|
|
165
|
-
base.define_action_method(parent_path + [:create]) do |
|
|
166
|
-
sl_exec_create(
|
|
167
|
+
base.define_action_method(parent_path + [:create]) do |short_link: {}, **ctx|
|
|
168
|
+
sl_exec_create(short_link, **ctx)
|
|
167
169
|
end
|
|
168
170
|
base.define_action_method(parent_path + [:list]) do |**ctx|
|
|
169
171
|
sl_exec_list(**sl_fetch_list(**ctx))
|
|
@@ -174,8 +176,8 @@ module Aspera
|
|
|
174
176
|
base.define_action_method(parent_path + [:delete]) do |**ctx|
|
|
175
177
|
sl_exec_delete(**sl_fetch_list(**ctx), **ctx)
|
|
176
178
|
end
|
|
177
|
-
base.define_action_method(parent_path + [:modify]) do |
|
|
178
|
-
sl_exec_modify(
|
|
179
|
+
base.define_action_method(parent_path + [:modify]) do |short_link: {}, **ctx|
|
|
180
|
+
sl_exec_modify(short_link, **sl_fetch_list(**ctx), **ctx)
|
|
179
181
|
end
|
|
180
182
|
end
|
|
181
183
|
end
|
|
@@ -187,7 +189,7 @@ module Aspera
|
|
|
187
189
|
pub_link_info = Api::AoC.link_info(app_url)
|
|
188
190
|
# public link case
|
|
189
191
|
if pub_link_info.key?(:token)
|
|
190
|
-
pub_api = Rest.new(base_url: "https://#{URI.parse(pub_link_info[:url]).host}/api/v1")
|
|
192
|
+
pub_api = Rest::Client.new(base_url: "https://#{URI.parse(pub_link_info[:url]).host}/api/v1")
|
|
191
193
|
pub_info = pub_api.read('env/url_token_check', {token: pub_link_info[:token]})
|
|
192
194
|
preset_value = {
|
|
193
195
|
link: app_url
|
|
@@ -198,8 +200,6 @@ module Aspera
|
|
|
198
200
|
test_args: 'organization'
|
|
199
201
|
}
|
|
200
202
|
end
|
|
201
|
-
options.declare(:use_generic_client, description: 'Wizard: AoC: use global or org specific jwt client id', allowed: Type::BOOLEAN, default: Api::AoC.saas_url?(app_url))
|
|
202
|
-
options.parse_options!
|
|
203
203
|
# make username mandatory for jwt, this triggers interactive input
|
|
204
204
|
wiz_username = options.get_option(:username, mandatory: true)
|
|
205
205
|
wizard.check_email(wiz_username)
|
|
@@ -216,7 +216,10 @@ module Aspera
|
|
|
216
216
|
client_id = options.get_option(:client_id)
|
|
217
217
|
client_secret = options.get_option(:client_secret)
|
|
218
218
|
if client_id.nil? || client_secret.nil?
|
|
219
|
-
|
|
219
|
+
use_generic_client = options.get_option(:use_generic_client)
|
|
220
|
+
# Default depends on URL
|
|
221
|
+
use_generic_client = Api::AoC.saas_url?(app_url) if use_generic_client.nil?
|
|
222
|
+
if use_generic_client
|
|
220
223
|
client_id = client_secret = nil
|
|
221
224
|
formatter.display_status('Using global client_id.')
|
|
222
225
|
else
|
|
@@ -270,6 +273,7 @@ module Aspera
|
|
|
270
273
|
option :new_user_option, description: 'New user creation option for unknown package recipients', allowed: [Hash, NilClass]
|
|
271
274
|
option :validate_metadata, description: 'Validate shared inbox metadata', allowed: Type::BOOLEAN, default: true
|
|
272
275
|
option :package_folder, schema: Schema::Registry::PACKAGE_FOLDER_OPTIONS
|
|
276
|
+
option :use_generic_client, description: 'Wizard: AoC: use global or org specific jwt client id (default: global for SaaS URL)', allowed: Type::BOOLEAN
|
|
273
277
|
|
|
274
278
|
use_options Node
|
|
275
279
|
|
|
@@ -279,7 +283,6 @@ module Aspera
|
|
|
279
283
|
@cache_home_node_file = nil
|
|
280
284
|
@cache_api_aoc = nil
|
|
281
285
|
@scope = Api::AoC::Scope::USER
|
|
282
|
-
options.parse_options!
|
|
283
286
|
end
|
|
284
287
|
|
|
285
288
|
# Change API scope for subsequent calls, re-instantiate API object
|
|
@@ -293,7 +296,7 @@ module Aspera
|
|
|
293
296
|
|
|
294
297
|
# Create an API object with the options from CLI, but with a different subpath
|
|
295
298
|
# @param base_path [String] Base path for APIs.
|
|
296
|
-
# @return [Api::AoC] API object for AoC (is Rest)
|
|
299
|
+
# @return [Api::AoC] API object for AoC (is Rest::Client)
|
|
297
300
|
def api_from_options(base_path)
|
|
298
301
|
# Get all existing OAuth kwargs from `options`.
|
|
299
302
|
api = Api::AoC.new(
|
|
@@ -318,7 +321,7 @@ module Aspera
|
|
|
318
321
|
end
|
|
319
322
|
|
|
320
323
|
# AoC Rest object
|
|
321
|
-
# @return [Api::AoC] API object for AoC (is Rest)
|
|
324
|
+
# @return [Api::AoC] API object for AoC (is Rest::Client)
|
|
322
325
|
def aoc_api
|
|
323
326
|
if @cache_api_aoc.nil?
|
|
324
327
|
@cache_api_aoc = api_from_options(Api::AoC::API_V1)
|
|
@@ -337,8 +340,8 @@ module Aspera
|
|
|
337
340
|
# @param name [Boolean] Include name
|
|
338
341
|
# @return [Hash{Symbol, String => String}] the modified hash containing:
|
|
339
342
|
# * `workspace_id` [String] the unique identifier.
|
|
340
|
-
# * `workspace_name` [String] (optional) the name, included if
|
|
341
|
-
# @note The key type (String or Symbol) depends on the
|
|
343
|
+
# * `workspace_name` [String] (optional) the name, included if `name` is true.
|
|
344
|
+
# @note The key type (String or Symbol) depends on the `string` parameter.
|
|
342
345
|
def workspace_id_hash(hash = nil, string: false, name: false)
|
|
343
346
|
info = aoc_api.workspace_info
|
|
344
347
|
hash = {} if hash.nil?
|
|
@@ -352,21 +355,6 @@ module Aspera
|
|
|
352
355
|
return hash
|
|
353
356
|
end
|
|
354
357
|
|
|
355
|
-
# Get resource identifier from command line, either directly specifying the `id` or from `name` (percent selector).
|
|
356
|
-
# @param resource_class_path [String] url path for resource
|
|
357
|
-
# @return [String] identifier
|
|
358
|
-
def get_resource_id_from_args(resource_class_path)
|
|
359
|
-
return options.instance_identifier do |field, value|
|
|
360
|
-
Aspera.assert_values(field, ['name'], type: BadArgument) { 'selector field' }
|
|
361
|
-
aoc_api.lookup_with_q(resource_class_path, value: value)['id']
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
# Get resource path from command line
|
|
366
|
-
def get_resource_path_from_args(resource_class_path)
|
|
367
|
-
return "#{resource_class_path}/#{get_resource_id_from_args(resource_class_path)}"
|
|
368
|
-
end
|
|
369
|
-
|
|
370
358
|
# List all entities, given additional, default and user's queries
|
|
371
359
|
# @param resource_class_path [String] path to query on API
|
|
372
360
|
# @param fields [Array, nil] fields to display
|
|
@@ -409,87 +397,98 @@ module Aspera
|
|
|
409
397
|
PACKAGE_RECEIVED_BASE_QUERY.each { |k, v| query[k] = v unless query.key?(k) }
|
|
410
398
|
resolve_dropbox_name_default_ws_id(query)
|
|
411
399
|
# Extract `max` before paging so callers can apply it after post-API filtering
|
|
412
|
-
max_items = query.delete(
|
|
400
|
+
max_items = query.delete(Rest::List::MAX_ITEMS)&.to_i
|
|
413
401
|
return aoc_api.read_with_paging('packages', query.compact), max_items
|
|
414
402
|
end
|
|
415
403
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
#
|
|
419
|
-
|
|
420
|
-
#
|
|
421
|
-
|
|
422
|
-
#
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
#
|
|
428
|
-
|
|
429
|
-
|
|
404
|
+
# Arguments of the node-to-node `transfer` command (files, admin node do, shared folder node)
|
|
405
|
+
TRANSFER_ARGS = [{name: :direction, allowed: %i[push pull]}, {name: :source_folder}].freeze
|
|
406
|
+
# Mount of the Node plugin Gen4 commands (`node access_keys do <id> ...`), instance: set per mount point
|
|
407
|
+
NODE_GEN4_MOUNT = {plugin: Node, at: %i[access_keys do]}.freeze
|
|
408
|
+
# Package identifier argument, `%name:` selector (lookup method shared with `admin package`)
|
|
409
|
+
PACKAGE_ID_ARG = {name: :package_id, type: :identifier, lookup: :lookup_aoc_package_id}.freeze
|
|
410
|
+
# Resource of analytics events (`admin analytics transfers|files`)
|
|
411
|
+
EVENT_RESOURCE_TYPE_ARG = {name: :event_resource_type, allowed: %i[organizations users nodes]}.freeze
|
|
412
|
+
EVENT_RESOURCE_ID_ARG = {name: :event_resource_id, description: 'Resource identifier, empty for the one of the current user'}.freeze
|
|
413
|
+
private_constant :TRANSFER_ARGS, :NODE_GEN4_MOUNT, :PACKAGE_ID_ARG, :EVENT_RESOURCE_TYPE_ARG, :EVENT_RESOURCE_ID_ARG
|
|
414
|
+
|
|
415
|
+
# Node API on a Gen4 node, and its root file id.
|
|
416
|
+
# @param node_id [String] Node identifier
|
|
417
|
+
# @param file_id [String, nil] Root file id; if nil, the access key root file id is used
|
|
418
|
+
# @param scope [String, nil] node scope (Api::Node::Scope::USER/ADMIN), or nil (requires secret)
|
|
419
|
+
# @return [Array(Api::Node, String)]
|
|
420
|
+
def nodegen4_root(node_id, file_id: nil, scope: nil)
|
|
421
|
+
node_api = aoc_api.node_api_from(
|
|
430
422
|
node_id: node_id,
|
|
431
423
|
scope: scope,
|
|
432
424
|
**workspace_id_hash(name: true)
|
|
433
425
|
)
|
|
434
|
-
file_id =
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
426
|
+
file_id = node_api.read("access_keys/#{node_api.app_info.node_info['access_key']}")['root_file_id'] if file_id.nil?
|
|
427
|
+
[node_api, file_id]
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Node plugin for Gen4 commands on a node, with the seed ctx of its `access_keys do` sub-tree.
|
|
431
|
+
# Used as `instance:` of mounts of NODE_GEN4_MOUNT.
|
|
432
|
+
# @return [Array(Node, Hash)]
|
|
433
|
+
def nodegen4_plugin(node_id, file_id: nil, scope: nil)
|
|
434
|
+
node_api, file_id = nodegen4_root(node_id, file_id: file_id, scope: scope)
|
|
435
|
+
[Node.new(context: context, api: node_api), {do_root_file_id: file_id}]
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
# Node-to-node transfer: client side is agent, server side is transfer server, in same workspace.
|
|
439
|
+
# @param direction [Symbol] :push or :pull
|
|
440
|
+
# @param source_folder [String] source folder
|
|
441
|
+
# @return [Result]
|
|
442
|
+
def nodegen4_transfer(node_id, direction:, source_folder:, file_id: nil, scope: nil)
|
|
443
|
+
top_node_api, file_id = nodegen4_root(node_id, file_id: file_id, scope: scope)
|
|
444
|
+
case direction
|
|
445
|
+
when :push
|
|
446
|
+
client_direction = Transfer::Spec::DIRECTION_SEND
|
|
447
|
+
client_folder = source_folder
|
|
448
|
+
server_folder = transfer.destination_folder(client_direction)
|
|
449
|
+
when :pull
|
|
450
|
+
client_direction = Transfer::Spec::DIRECTION_RECEIVE
|
|
451
|
+
client_folder = transfer.destination_folder(client_direction)
|
|
452
|
+
server_folder = source_folder
|
|
453
|
+
else Aspera.error_unexpected_value(direction) { 'direction' }
|
|
454
|
+
end
|
|
455
|
+
client_apifid = top_node_api.resolve_api_fid(file_id, client_folder)
|
|
456
|
+
server_apifid = top_node_api.resolve_api_fid(file_id, server_folder)
|
|
457
|
+
# force node as transfer agent
|
|
458
|
+
transfer.agent_instance = Agent::Node.new(
|
|
459
|
+
url: client_apifid.node_api.base_url,
|
|
460
|
+
username: client_apifid.node_api.app_info.node_info['access_key'],
|
|
461
|
+
password: client_apifid.node_api.oauth.authorization,
|
|
462
|
+
root_id: client_apifid.file_id
|
|
463
|
+
)
|
|
464
|
+
# additional node to node TS info
|
|
465
|
+
add_ts = {
|
|
466
|
+
'remote_access_key' => server_apifid.node_api.app_info.node_info['access_key'],
|
|
467
|
+
'destination_root_id' => server_apifid.file_id,
|
|
468
|
+
'source_root_id' => client_apifid.file_id
|
|
469
|
+
}
|
|
470
|
+
Runner.result_transfer(transfer.start(server_apifid.node_api.transfer_spec_gen4(
|
|
471
|
+
server_apifid.file_id,
|
|
472
|
+
client_direction,
|
|
473
|
+
add_ts
|
|
474
|
+
)))
|
|
482
475
|
end
|
|
483
476
|
|
|
484
477
|
# Execute an action on admin resources
|
|
485
478
|
# @param resource_type [Symbol] One of ADMIN_OBJECTS
|
|
486
479
|
# Per-resource configuration for admin CRUD resources.
|
|
487
|
-
# Keys: path, list_fields, id_result, require_ws_id, create_schema, extra_ops, singleton, op_setup
|
|
480
|
+
# Keys: path, list_fields, id_result, require_ws_id, create_schema, extra_ops, singleton, op_setup, op_mount, op_descriptions
|
|
488
481
|
# op_setup: Hash of op => setup method name, used for ops that require consuming an instance identifier.
|
|
489
482
|
# For Operations::INSTANCE ops (show/modify/delete), use the auto-generated :setup_admin_<res>_instance.
|
|
490
483
|
# For extra_ops that are instance ops, specify explicitly (or rely on the auto-generated one).
|
|
484
|
+
# op_mount: Hash of op => mount: of that op's node.
|
|
485
|
+
# op_descriptions: Hash of op => description, for ops other than standard ones.
|
|
491
486
|
ADMIN_OBJECT_CONFIG = {
|
|
492
|
-
client: {
|
|
487
|
+
client: {
|
|
488
|
+
extra_ops: %i[set_pub_key],
|
|
489
|
+
extra_op_args: {set_pub_key: [{name: :private_key_pem}]},
|
|
490
|
+
op_descriptions: {set_pub_key: 'Set public key of client from a private key'}
|
|
491
|
+
},
|
|
493
492
|
client_access_key: {path: 'admin/client_access_keys'},
|
|
494
493
|
client_registration_token: {path: 'admin/client_registration_tokens', list_fields: %w[id value data.client_subject_scopes data.name created_at], id_result: 'token'},
|
|
495
494
|
configuration_policy: {list_fields: nil},
|
|
@@ -500,15 +499,30 @@ module Aspera
|
|
|
500
499
|
group_membership: {list_fields: %w[id group_id member_type member_id], create_schema: false},
|
|
501
500
|
kms_profile: {path: 'integrations/kms_profiles', create_schema: false},
|
|
502
501
|
network_policy: {list_fields: nil},
|
|
503
|
-
node: {
|
|
502
|
+
node: {
|
|
503
|
+
list_fields: %w[id name host access_key],
|
|
504
|
+
extra_ops: %i[do bearer_token update_status],
|
|
505
|
+
extra_op_args: {bearer_token: [{name: :scope, mandatory: false, default: nil}]},
|
|
506
|
+
op_mount: {do: NODE_GEN4_MOUNT.merge(instance: :admin_node_do_plugin)},
|
|
507
|
+
op_descriptions: {do: 'Execute command on node', bearer_token: 'Generate bearer token for node', update_status: 'Ask AoC to scan node and update its status'}
|
|
508
|
+
},
|
|
504
509
|
operation: {list_fields: %w[id type status created_at updated_at workspace_id user_id workspace_membership_id group_membership_id], ops: %i[list show modify]},
|
|
505
510
|
organization: {singleton: true},
|
|
506
511
|
package: {},
|
|
507
512
|
saml_configuration: {create_schema: false},
|
|
508
|
-
self: {singleton: true},
|
|
513
|
+
self: {singleton: true, op_descriptions: {show: 'Show current user'}},
|
|
509
514
|
short_link: {list_fields: %w[id short_url data.url_token_data.purpose password_enabled password_protected updated_by_user_id updated_at]},
|
|
510
|
-
user: {
|
|
511
|
-
|
|
515
|
+
user: {
|
|
516
|
+
list_fields: %w[id name email],
|
|
517
|
+
extra_ops: %i[preferences notifications],
|
|
518
|
+
op_setup: {preferences: :setup_admin_user_instance, notifications: :setup_admin_user_instance},
|
|
519
|
+
op_descriptions: {preferences: 'Manage user preferences', notifications: 'Manage user notification preferences'}
|
|
520
|
+
},
|
|
521
|
+
workspace: {
|
|
522
|
+
extra_ops: %i[shared_folder dropbox],
|
|
523
|
+
op_setup: {shared_folder: :setup_admin_workspace_shared_folder, dropbox: :setup_admin_workspace_dropbox},
|
|
524
|
+
op_descriptions: {shared_folder: 'Manage shared folders of workspace', dropbox: 'Manage shared inboxes of workspace'}
|
|
525
|
+
},
|
|
512
526
|
workspace_membership: {list_fields: %w[id workspace_id member_type member_id]}
|
|
513
527
|
}.freeze
|
|
514
528
|
private_constant :ADMIN_OBJECT_CONFIG
|
|
@@ -524,14 +538,14 @@ module Aspera
|
|
|
524
538
|
|
|
525
539
|
# Build analytics REST API (shared by action_admin_analytics_*)
|
|
526
540
|
def build_analytics_api
|
|
527
|
-
Rest.new(**aoc_api.params.deep_merge({
|
|
541
|
+
Rest::Client.new(**aoc_api.params.deep_merge({
|
|
528
542
|
base_url: "#{aoc_api.base_url.gsub('/api/v1', '')}/analytics/v2",
|
|
529
543
|
auth: {params: {scope: Api::AoC::Scope::ADMIN_USER}}
|
|
530
544
|
}))
|
|
531
545
|
end
|
|
532
546
|
|
|
533
547
|
# Compute short-link purposes from shared_data keys and link_type.
|
|
534
|
-
# @param shared_data [Hash] :dropbox_id
|
|
548
|
+
# @param shared_data [Hash] :dropbox_id + :name or :file_id + :node_id
|
|
535
549
|
# @param link_type [Symbol] :public or :private
|
|
536
550
|
# @return [Array(String,String)] [token_purpose, short_link_purpose]
|
|
537
551
|
def short_link_purposes(shared_data, link_type)
|
|
@@ -591,35 +605,39 @@ module Aspera
|
|
|
591
605
|
command :reminder, description: 'Send reminder email with list of orgs'
|
|
592
606
|
command(
|
|
593
607
|
:servers, description: 'List AoC servers (no auth)',
|
|
594
|
-
action: lambda do
|
|
608
|
+
action: lambda do |**|
|
|
595
609
|
no_auth_api = Api::AoC.new(url: options.get_option(:url), auth: :none)
|
|
596
610
|
Result::ObjectList.new(no_auth_api.read('servers'))
|
|
597
611
|
end
|
|
598
612
|
)
|
|
599
|
-
command :bearer_token, description: '
|
|
600
|
-
action: -> { Result::Text.new(aoc_api.oauth.authorization) }
|
|
613
|
+
command :bearer_token, description: 'Show bearer token',
|
|
614
|
+
action: ->(**) { Result::Text.new(aoc_api.oauth.authorization) }
|
|
601
615
|
command :organization, description: 'Show organization info',
|
|
602
|
-
action: -> { Result::SingleObject.new(aoc_api.read('organization')) }
|
|
616
|
+
action: ->(**) { Result::SingleObject.new(aoc_api.read('organization')) }
|
|
603
617
|
command :tier_restrictions, description: 'Show tier restrictions',
|
|
604
|
-
action: -> { Result::SingleObject.new(aoc_api.read('tier_restrictions')) }
|
|
605
|
-
command :user, description: '
|
|
606
|
-
|
|
607
|
-
command :
|
|
608
|
-
|
|
618
|
+
action: ->(**) { Result::SingleObject.new(aoc_api.read('tier_restrictions')) }
|
|
619
|
+
command :user, description: 'Manage current user'
|
|
620
|
+
# Node Gen4 read-only commands on packages: `packages <command> <package_id> ...`
|
|
621
|
+
command :packages, description: 'Manage packages', setup: :setup_workspace_display,
|
|
622
|
+
mount: NODE_GEN4_MOUNT.merge(instance: :package_node_plugin, only: Node::NODE4_READ_ACTIONS, arguments: [PACKAGE_ID_ARG])
|
|
623
|
+
command :files, description: 'Manage files (workspace-aware)', setup: :setup_workspace_display,
|
|
624
|
+
mount: NODE_GEN4_MOUNT.merge(instance: :files_node_plugin)
|
|
625
|
+
command :admin, description: 'Administer AoC', setup: :setup_admin_scope
|
|
609
626
|
commands_under :admin do
|
|
610
627
|
command :bearer_token, description: 'Show admin bearer token',
|
|
611
|
-
action: -> { Result::Text.new(aoc_api.oauth.authorization) }
|
|
628
|
+
action: ->(**) { Result::Text.new(aoc_api.oauth.authorization) }
|
|
612
629
|
command :application, description: 'Manage applications'
|
|
613
630
|
command :ats, description: 'Manage ATS (Aspera Transfer Service)',
|
|
614
|
-
|
|
631
|
+
mount: {plugin: Ats, instance: :build_ats_plugin}
|
|
615
632
|
command :usage_reports, description: 'List usage reports',
|
|
616
|
-
action: -> { result_list('usage_reports', base_query: workspace_id_hash) }
|
|
633
|
+
action: ->(**) { result_list('usage_reports', base_query: workspace_id_hash) }
|
|
617
634
|
command :auth_providers, description: 'Manage auth providers'
|
|
618
635
|
command :subscription, description: 'Show subscription info'
|
|
619
636
|
command :analytics, description: 'Query analytics'
|
|
620
637
|
ADMIN_OBJECTS.each do |res|
|
|
621
638
|
cfg = ADMIN_OBJECT_CONFIG.fetch(res, {})
|
|
622
639
|
op_setup = cfg[:op_setup] || {}
|
|
640
|
+
op_mount = cfg[:op_mount] || {}
|
|
623
641
|
extra_op_args = cfg[:extra_op_args] || {}
|
|
624
642
|
is_singleton = cfg[:singleton]
|
|
625
643
|
id_arg_spec = is_singleton ? [] : [{name: :"#{res}_id", type: :identifier, lookup: :"lookup_aoc_#{res}_id"}]
|
|
@@ -630,18 +648,19 @@ module Aspera
|
|
|
630
648
|
else
|
|
631
649
|
Operations::ALL + (cfg[:extra_ops] || [])
|
|
632
650
|
end
|
|
633
|
-
command res, description: "Manage #{res
|
|
651
|
+
command res, description: "Manage #{entity_noun(res, singular: false)}"
|
|
634
652
|
commands_under res do
|
|
635
653
|
ops.each do |op|
|
|
636
654
|
extra_setup = op_setup[op]
|
|
637
655
|
base_attrs = extra_setup ? {setup: extra_setup} : {}
|
|
656
|
+
base_attrs[:mount] = op_mount[op] if op_mount.key?(op)
|
|
638
657
|
extra_arg_list =
|
|
639
658
|
if !is_singleton && op.eql?(:create)
|
|
640
659
|
c = aoc_res_cfg(res)
|
|
641
|
-
[{name:
|
|
660
|
+
[{name: res, type: Hash, bulk: true, schema: c[:schema]}]
|
|
642
661
|
elsif !is_singleton && op.eql?(:modify)
|
|
643
662
|
c = aoc_res_cfg(res)
|
|
644
|
-
[{name:
|
|
663
|
+
[{name: res, type: Hash, schema: c[:schema]}]
|
|
645
664
|
elsif extra_op_args.key?(op)
|
|
646
665
|
extra_op_args[op]
|
|
647
666
|
else
|
|
@@ -655,62 +674,71 @@ module Aspera
|
|
|
655
674
|
c = aoc_res_cfg(res)
|
|
656
675
|
merged = merged.merge(query_schema: Schema::Registry.query_params(c[:query_component], c[:path]))
|
|
657
676
|
end
|
|
658
|
-
|
|
677
|
+
description = cfg.dig(:op_descriptions, op) ||
|
|
678
|
+
(Operations::ALL.include?(op) ? operation_description(op, entity_noun(res, singular: false)) : op.to_s.tr('_', ' ').capitalize)
|
|
679
|
+
command op, description: description, **merged
|
|
659
680
|
end
|
|
660
681
|
end
|
|
661
682
|
end
|
|
662
683
|
end
|
|
663
684
|
# admin > workspace > shared_folder sub-tree
|
|
664
685
|
commands_under %i[admin workspace shared_folder] do
|
|
665
|
-
command :list, description: 'List shared folders'
|
|
686
|
+
command :list, description: 'List shared folders',
|
|
687
|
+
action: ->(shared_folders:, **) { Result::ObjectList.new(shared_folders, fields: %w[id node_name node_id file_id file.path tags.aspera.files.workspace.share_as]) }
|
|
666
688
|
command :node, description: 'Execute node command on shared folder',
|
|
667
|
-
arguments: [{name: :
|
|
668
|
-
setup: :setup_admin_workspace_shared_folder_node
|
|
689
|
+
arguments: [{name: :shared_folder_id, type: :identifier}],
|
|
690
|
+
setup: :setup_admin_workspace_shared_folder_node,
|
|
691
|
+
mount: NODE_GEN4_MOUNT.merge(instance: :admin_workspace_shared_folder_node_plugin)
|
|
669
692
|
command :member, description: 'Show folder members',
|
|
670
|
-
arguments: [{name: :
|
|
693
|
+
arguments: [{name: :shared_folder_id, type: :identifier}],
|
|
671
694
|
setup: :setup_admin_workspace_shared_folder_member
|
|
672
695
|
end
|
|
673
|
-
# admin > workspace > shared_folder > node
|
|
696
|
+
# admin > workspace > shared_folder > node: Gen4 commands are mounted, plus node-to-node transfer
|
|
674
697
|
commands_under %i[admin workspace shared_folder node] do
|
|
675
|
-
command :transfer,
|
|
676
|
-
|
|
677
|
-
command :sync, description: 'Synchronize folders'
|
|
678
|
-
Node::COMMANDS_GEN4_SPEC.each do |cmd, spec|
|
|
679
|
-
command cmd, **spec
|
|
680
|
-
end
|
|
698
|
+
command :transfer, description: 'Transfer files (node-to-node)', arguments: TRANSFER_ARGS,
|
|
699
|
+
action: ->(sf_item:, direction:, source_folder:, **) { nodegen4_transfer(sf_item['node_id'], file_id: sf_item['file_id'], scope: Api::Node::Scope::ADMIN, direction: direction, source_folder: source_folder) }
|
|
681
700
|
end
|
|
682
701
|
commands_under %i[admin workspace shared_folder member] do
|
|
683
702
|
command :list, description: 'List members of a shared folder'
|
|
684
703
|
end
|
|
685
704
|
# admin > workspace > dropbox sub-tree
|
|
686
705
|
commands_under %i[admin workspace dropbox] do
|
|
687
|
-
command
|
|
706
|
+
command(
|
|
707
|
+
:list, description: 'List dropboxes in workspace',
|
|
708
|
+
action: lambda do |ws_res_id:, **|
|
|
709
|
+
query = query_read_delete(default: {}, schema: Schema::Registry.query_params(Schema::Registry::AOC, 'dropboxes'))
|
|
710
|
+
Result::ObjectList.new(aoc_api.read('dropboxes', query.merge({'workspace_id' => ws_res_id})), fields: %w[id name description])
|
|
711
|
+
end
|
|
712
|
+
)
|
|
688
713
|
end
|
|
689
|
-
# admin > node > do
|
|
714
|
+
# admin > node > do: Gen4 commands are mounted (op_mount), plus node-to-node transfer
|
|
690
715
|
commands_under %i[admin node do] do
|
|
691
|
-
command :transfer,
|
|
692
|
-
|
|
693
|
-
command :sync, description: 'Synchronize folders'
|
|
694
|
-
Node::COMMANDS_GEN4_SPEC.each do |cmd, spec|
|
|
695
|
-
command cmd, **spec
|
|
696
|
-
end
|
|
716
|
+
command :transfer, description: 'Transfer files (node-to-node)', arguments: TRANSFER_ARGS,
|
|
717
|
+
action: ->(node_id:, direction:, source_folder:, **) { nodegen4_transfer(node_id, scope: Api::Node::Scope::ADMIN, direction: direction, source_folder: source_folder) }
|
|
697
718
|
end
|
|
698
719
|
# admin > user > preferences|notifications sub-trees
|
|
699
720
|
%i[preferences notifications].each do |pref|
|
|
700
|
-
commands_under
|
|
701
|
-
command :show, description: "Show #{pref}"
|
|
702
|
-
command :modify, description: "Modify #{pref}",
|
|
703
|
-
arguments: [{name:
|
|
721
|
+
commands_under [:admin, :user, pref] do
|
|
722
|
+
command :show, description: "Show user #{pref}"
|
|
723
|
+
command :modify, description: "Modify user #{pref}",
|
|
724
|
+
arguments: [{name: pref, type: Hash}]
|
|
704
725
|
end
|
|
705
726
|
end
|
|
706
727
|
commands_under %i[admin auth_providers] do
|
|
707
728
|
command :list, description: 'List auth providers',
|
|
708
|
-
action: -> { result_list('admin/auth_providers') }
|
|
709
|
-
command :update, description: 'Update auth provider', action: -> { Aspera.error_not_implemented }
|
|
729
|
+
action: ->(**) { result_list('admin/auth_providers') }
|
|
730
|
+
command :update, description: 'Update auth provider', action: ->(**) { Aspera.error_not_implemented }
|
|
710
731
|
end
|
|
711
732
|
commands_under %i[admin subscription] do
|
|
712
|
-
command
|
|
713
|
-
|
|
733
|
+
command(
|
|
734
|
+
:account, description: 'Show subscription account',
|
|
735
|
+
action: lambda do |**|
|
|
736
|
+
org = aoc_api.read('organization')
|
|
737
|
+
result = GraphQL.execute(api_from_options('bss/platform/graphql'), 'bss_subscription_account', {organization_id: org['id']})
|
|
738
|
+
Result::SingleObject.new(result['aoc']['bssSubscription'])
|
|
739
|
+
end
|
|
740
|
+
)
|
|
741
|
+
command :usage, description: 'Show subscription usage',
|
|
714
742
|
arguments: [
|
|
715
743
|
{name: :aggregate, mandatory: false, default: :ALL, allowed: %i[ALL MONTHLY]},
|
|
716
744
|
{name: :start_date, mandatory: false, default: nil},
|
|
@@ -718,23 +746,29 @@ module Aspera
|
|
|
718
746
|
]
|
|
719
747
|
end
|
|
720
748
|
commands_under %i[admin analytics] do
|
|
721
|
-
command
|
|
749
|
+
command(
|
|
750
|
+
:application_events, description: 'List application events',
|
|
751
|
+
action: lambda do |**|
|
|
752
|
+
events = build_analytics_api.read("organizations/#{aoc_api.current_user_info['organization_id']}/application_events")['application_events']
|
|
753
|
+
Result::ObjectList.new(events)
|
|
754
|
+
end
|
|
755
|
+
)
|
|
722
756
|
command :transfers, description: 'List transfer events',
|
|
723
757
|
arguments: [
|
|
724
|
-
|
|
725
|
-
|
|
758
|
+
EVENT_RESOURCE_TYPE_ARG,
|
|
759
|
+
EVENT_RESOURCE_ID_ARG.merge(mandatory: false, default: nil)
|
|
726
760
|
]
|
|
727
761
|
command :files, description: 'List file events',
|
|
728
762
|
arguments: [
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
{name: :event_uuid,
|
|
763
|
+
EVENT_RESOURCE_TYPE_ARG,
|
|
764
|
+
EVENT_RESOURCE_ID_ARG,
|
|
765
|
+
{name: :event_uuid, type: :identifier}
|
|
732
766
|
]
|
|
733
767
|
end
|
|
734
768
|
# application sub-commands
|
|
735
769
|
commands_under %i[admin application] do
|
|
736
770
|
command :types, description: 'List application types',
|
|
737
|
-
action: -> { Result::ObjectList.new(aoc_api.read('admin/apps')) }
|
|
771
|
+
action: ->(**) { Result::ObjectList.new(aoc_api.read('admin/apps')) }
|
|
738
772
|
command :settings, description: 'Manage per-app-type settings'
|
|
739
773
|
command :instance, description: 'Manage app instances'
|
|
740
774
|
command :membership, description: 'Manage app memberships'
|
|
@@ -744,15 +778,15 @@ module Aspera
|
|
|
744
778
|
private_constant :APP_SETTINGS_PATH, :APP_INSTANCE_PATH
|
|
745
779
|
commands_under APP_SETTINGS_PATH do
|
|
746
780
|
APP_TYPES.each do |app_type|
|
|
747
|
-
command app_type, description: "
|
|
781
|
+
command app_type, description: "Manage settings of #{app_type} app"
|
|
748
782
|
commands_under app_type do
|
|
749
783
|
command :show, description: "Show #{app_type} settings",
|
|
750
|
-
action: -> { Result::SingleObject.new(aoc_api.read("/apps/#{app_type}/settings")) }
|
|
784
|
+
action: ->(**) { Result::SingleObject.new(aoc_api.read("/apps/#{app_type}/settings")) }
|
|
751
785
|
command(
|
|
752
786
|
:modify, description: "Modify #{app_type} settings",
|
|
753
|
-
arguments: [{name: :
|
|
754
|
-
action: lambda do |
|
|
755
|
-
aoc_api.update("/apps/#{app_type}/settings",
|
|
787
|
+
arguments: [{name: :settings, type: Hash}],
|
|
788
|
+
action: lambda do |settings:, **|
|
|
789
|
+
aoc_api.update("/apps/#{app_type}/settings", settings)
|
|
756
790
|
Result::Status.new('modified')
|
|
757
791
|
end
|
|
758
792
|
)
|
|
@@ -760,57 +794,63 @@ module Aspera
|
|
|
760
794
|
end
|
|
761
795
|
end
|
|
762
796
|
commands_under APP_INSTANCE_PATH do
|
|
763
|
-
command
|
|
764
|
-
result_list(
|
|
765
|
-
'admin/apps_new',
|
|
766
|
-
fields: %w[id app_type available workspace_id],
|
|
767
|
-
default_query: {workspace_id: aoc_api.workspace_info[:id]}
|
|
768
|
-
)
|
|
769
|
-
end)
|
|
797
|
+
command :list, description: 'List app instances'
|
|
770
798
|
APP_TYPES.each do |app_type|
|
|
771
|
-
command app_type, description: "
|
|
799
|
+
command app_type, description: "Manage #{app_type} app instance"
|
|
772
800
|
commands_under app_type do
|
|
773
|
-
command :show, description: "Show
|
|
774
|
-
arguments: [{name: :
|
|
775
|
-
command :modify, description: "Modify
|
|
776
|
-
arguments: [{name: :
|
|
801
|
+
command :show, description: "Show #{app_type} instance",
|
|
802
|
+
arguments: [{name: :instance_id, type: :identifier}]
|
|
803
|
+
command :modify, description: "Modify #{app_type} instance",
|
|
804
|
+
arguments: [{name: :instance_id, type: :identifier}, {name: :instance, type: Hash}]
|
|
777
805
|
end
|
|
778
806
|
end
|
|
779
807
|
end
|
|
780
808
|
commands_under %i[admin application membership] do
|
|
781
|
-
command :list, description: 'List app memberships', action: -> { result_list('apps/app_memberships') }
|
|
782
|
-
command :show,
|
|
783
|
-
|
|
809
|
+
command :list, description: 'List app memberships', action: ->(**) { result_list('apps/app_memberships') }
|
|
810
|
+
command :show, description: 'Show an app membership', arguments: [{name: :membership_id, type: :identifier}],
|
|
811
|
+
action: ->(membership_id:, **) { Result::SingleObject.new(aoc_api.read("apps/app_memberships/#{membership_id}", query_read_delete)) }
|
|
812
|
+
command(
|
|
813
|
+
:delete, description: 'Delete an app membership', arguments: [{name: :membership_id, type: :identifier}],
|
|
814
|
+
action: lambda do |membership_id:, **|
|
|
815
|
+
aoc_api.delete("apps/app_memberships/#{membership_id}")
|
|
816
|
+
Result::Status.new('deleted')
|
|
817
|
+
end
|
|
818
|
+
)
|
|
784
819
|
command :create, description: 'Create an app membership', arguments: [{name: :membership, type: Hash}]
|
|
785
820
|
end
|
|
786
|
-
command :automation, description: '
|
|
821
|
+
command :automation, description: 'Manage automation (BETA)', setup: :setup_automation_api
|
|
787
822
|
command :gateway, description: 'Start AoC Faspex4 gateway',
|
|
788
823
|
arguments: [{name: :parameters, type: Hash, mandatory: false, default: {}}]
|
|
789
824
|
|
|
790
825
|
# user sub-commands
|
|
791
826
|
commands_under :user do
|
|
792
|
-
commands_under :workspaces, description: "
|
|
793
|
-
command :list, description: 'List workspaces', action: -> { result_list('workspaces', fields: %w[id name]) }
|
|
794
|
-
command :current, description: 'Show current workspace', action: -> { Result::SingleObject.new(aoc_api.workspace_info) }
|
|
827
|
+
commands_under :workspaces, description: "Manage user's workspaces" do
|
|
828
|
+
command :list, description: 'List workspaces', action: ->(**) { result_list('workspaces', fields: %w[id name]) }
|
|
829
|
+
command :current, description: 'Show current workspace', action: ->(**) { Result::SingleObject.new(aoc_api.workspace_info) }
|
|
795
830
|
end
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
command :show, description: 'Show user profile', action: -> { Result::SingleObject.new(aoc_api.current_user_info(exception: true)) }
|
|
831
|
+
commands_under :profile, description: "Manage user's profile" do
|
|
832
|
+
command :show, description: 'Show user profile', action: ->(**) { Result::SingleObject.new(aoc_api.current_user_info(exception: true)) }
|
|
799
833
|
command(
|
|
800
834
|
:modify, description: 'Modify user profile',
|
|
801
|
-
arguments: [{name: :
|
|
802
|
-
action: lambda do |
|
|
803
|
-
aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}",
|
|
835
|
+
arguments: [{name: :profile, type: Hash}],
|
|
836
|
+
action: lambda do |profile:, **|
|
|
837
|
+
aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}", profile)
|
|
804
838
|
Result::Status.new('modified')
|
|
805
839
|
end
|
|
806
840
|
)
|
|
807
841
|
end
|
|
808
|
-
command :preferences, description: '
|
|
809
|
-
command :notifications, description: '
|
|
842
|
+
command :preferences, description: 'Manage interaction preferences'
|
|
843
|
+
command :notifications, description: 'Manage notification preferences'
|
|
810
844
|
command :contacts, description: 'Manage contacts'
|
|
811
845
|
# user > contacts sub-commands (same CRUD as admin > contact)
|
|
812
846
|
commands_under %i[contacts] do
|
|
813
|
-
|
|
847
|
+
contact_id = {name: :contact_id, type: :identifier, lookup: :lookup_aoc_contact_id}
|
|
848
|
+
contact_schema = aoc_res_cfg(:contact)[:schema]
|
|
849
|
+
command :list, description: operation_description(:list, 'contact')
|
|
850
|
+
command :show, description: operation_description(:show, 'contact'), arguments: [contact_id]
|
|
851
|
+
command :create, description: operation_description(:create, 'contact'), arguments: [{name: :contact, type: Hash, bulk: true, schema: contact_schema}]
|
|
852
|
+
command :modify, description: operation_description(:modify, 'contact'), arguments: [contact_id, {name: :contact, type: Hash, schema: contact_schema}]
|
|
853
|
+
command :delete, description: operation_description(:delete, 'contact'), arguments: [contact_id]
|
|
814
854
|
end
|
|
815
855
|
command :settings, description: 'Manage client settings'
|
|
816
856
|
commands_under %i[settings] do
|
|
@@ -821,17 +861,17 @@ module Aspera
|
|
|
821
861
|
commands_under %i[user preferences] do
|
|
822
862
|
command(
|
|
823
863
|
:show, description: 'Show user preferences',
|
|
824
|
-
action: lambda do
|
|
864
|
+
action: lambda do |**|
|
|
825
865
|
user_id = aoc_api.current_user_info(exception: true)['id']
|
|
826
866
|
Result::SingleObject.new(aoc_api.read("users/#{user_id}/user_interaction_preferences"))
|
|
827
867
|
end
|
|
828
868
|
)
|
|
829
869
|
command(
|
|
830
870
|
:modify, description: 'Modify user preferences',
|
|
831
|
-
arguments: [{name: :
|
|
832
|
-
action: lambda do |
|
|
871
|
+
arguments: [{name: :preferences, type: Hash}],
|
|
872
|
+
action: lambda do |preferences:, **|
|
|
833
873
|
user_id = aoc_api.current_user_info(exception: true)['id']
|
|
834
|
-
aoc_api.update("users/#{user_id}/user_interaction_preferences",
|
|
874
|
+
aoc_api.update("users/#{user_id}/user_interaction_preferences", preferences)
|
|
835
875
|
Result::Status.new('modified')
|
|
836
876
|
end
|
|
837
877
|
)
|
|
@@ -840,100 +880,146 @@ module Aspera
|
|
|
840
880
|
commands_under %i[user notifications] do
|
|
841
881
|
command(
|
|
842
882
|
:show, description: 'Show notification preferences',
|
|
843
|
-
action: lambda do
|
|
883
|
+
action: lambda do |**|
|
|
844
884
|
user_id = aoc_api.current_user_info(exception: true)['id']
|
|
845
885
|
Result::SingleObject.new(aoc_api.read("users/#{user_id}/notification_preferences"))
|
|
846
886
|
end
|
|
847
887
|
)
|
|
848
888
|
command(
|
|
849
889
|
:modify, description: 'Modify notification preferences',
|
|
850
|
-
arguments: [{name: :
|
|
851
|
-
action: lambda do |
|
|
890
|
+
arguments: [{name: :notifications, type: Hash}],
|
|
891
|
+
action: lambda do |notifications:, **|
|
|
852
892
|
user_id = aoc_api.current_user_info(exception: true)['id']
|
|
853
|
-
aoc_api.update("users/#{user_id}/notification_preferences",
|
|
893
|
+
aoc_api.update("users/#{user_id}/notification_preferences", notifications)
|
|
854
894
|
Result::Status.new('modified')
|
|
855
895
|
end
|
|
856
896
|
)
|
|
857
897
|
end
|
|
858
898
|
|
|
859
899
|
# packages sub-commands — instance commands consume package_id
|
|
900
|
+
# Not `crud_commands`: `list` has its own query and `once_only` persistency.
|
|
860
901
|
commands_under :packages do
|
|
861
|
-
command :shared_inboxes, description: '
|
|
902
|
+
command :shared_inboxes, description: 'Manage shared inboxes'
|
|
862
903
|
command :send, description: 'Send a package', transfer_paths: :send,
|
|
863
|
-
arguments: [{name: :
|
|
904
|
+
arguments: [{name: :package, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::AOC, 'packages.post')}]
|
|
864
905
|
command :receive, description: 'Receive packages', aliases: [:recv], transfer_paths: :receive,
|
|
865
|
-
arguments: [
|
|
906
|
+
arguments: [PACKAGE_ID_ARG]
|
|
866
907
|
command :list, description: 'List packages'
|
|
867
908
|
command :show, description: 'Show a package',
|
|
868
|
-
arguments: [
|
|
909
|
+
arguments: [PACKAGE_ID_ARG],
|
|
910
|
+
action: ->(package_id:, **) { Result::SingleObject.new(aoc_api.read("packages/#{package_id}")) }
|
|
869
911
|
command :delete, description: 'Delete packages',
|
|
870
|
-
arguments: [
|
|
871
|
-
command
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
arguments: [{name: :package_id, type: :identifier}]
|
|
880
|
-
command :find, description: 'Find files in package',
|
|
881
|
-
arguments: [{name: :package_id, type: :identifier}]
|
|
912
|
+
arguments: [PACKAGE_ID_ARG.merge(bulk: true)]
|
|
913
|
+
command(
|
|
914
|
+
:modify, description: 'Modify a package',
|
|
915
|
+
arguments: [PACKAGE_ID_ARG, {name: :package, type: Hash}],
|
|
916
|
+
action: lambda do |package:, package_id:, **|
|
|
917
|
+
aoc_api.update("packages/#{package_id}", package)
|
|
918
|
+
Result::Status.new('modified')
|
|
919
|
+
end
|
|
920
|
+
)
|
|
882
921
|
end
|
|
883
922
|
|
|
884
923
|
commands_under %i[packages shared_inboxes] do
|
|
885
|
-
command :list, description: 'List shared inboxes'
|
|
886
|
-
action: (lambda do
|
|
887
|
-
result_list(
|
|
888
|
-
'dropbox_memberships',
|
|
889
|
-
fields: %w[dropbox_id dropbox.name],
|
|
890
|
-
default_query: workspace_id_hash({'embed[]' => 'dropbox', 'aggregate_permissions_by_dropbox' => true, 'sort' => 'dropbox_name'}, string: true)
|
|
891
|
-
)
|
|
892
|
-
end)
|
|
924
|
+
command :list, description: 'List shared inboxes'
|
|
893
925
|
command :show, description: 'Show a shared inbox',
|
|
894
926
|
arguments: [{name: :dropbox_id, type: :identifier, lookup: :lookup_aoc_dropbox_id}],
|
|
895
927
|
action: ->(dropbox_id:, **) { Result::SingleObject.new(aoc_api.read("dropboxes/#{dropbox_id}")) }
|
|
896
928
|
command :short_link, description: 'Manage shared inbox short links',
|
|
897
|
-
arguments: [{name: :link_type, allowed: %i[public private]}],
|
|
929
|
+
arguments: [{name: :link_type, allowed: %i[public private]}, {name: :dropbox_id, type: :identifier, lookup: :lookup_aoc_dropbox_id}],
|
|
898
930
|
setup: :setup_packages_short_link
|
|
899
931
|
end
|
|
900
932
|
# packages > shared_inboxes > short_link sub-commands
|
|
901
933
|
register_short_link_commands(self, %i[packages shared_inboxes short_link])
|
|
902
934
|
|
|
903
|
-
# files sub-commands:
|
|
935
|
+
# files sub-commands: Gen4 commands are mounted, plus AoC-specific commands
|
|
904
936
|
commands_under :files do
|
|
905
937
|
command :short_link, description: 'Manage file short link',
|
|
906
|
-
arguments: [{name: :
|
|
938
|
+
arguments: [{name: :folder}, {name: :link_type, allowed: %i[public private]}],
|
|
907
939
|
setup: :setup_files_short_link
|
|
908
|
-
command :transfer, description: 'Transfer files (node-to-node)',
|
|
909
|
-
|
|
910
|
-
command :permission, description: 'Manage permissions'
|
|
911
|
-
command :sync, description: 'Synchronize folders'
|
|
912
|
-
Node::COMMANDS_GEN4_SPEC.each do |cmd, spec|
|
|
913
|
-
command cmd, **spec
|
|
914
|
-
end
|
|
940
|
+
command :transfer, description: 'Transfer files (node-to-node)', arguments: TRANSFER_ARGS,
|
|
941
|
+
action: ->(direction:, source_folder:, **) { nodegen4_transfer(aoc_api.home[:node_id], file_id: aoc_api.home[:file_id], scope: Api::Node::Scope::USER, direction: direction, source_folder: source_folder) }
|
|
915
942
|
end
|
|
916
943
|
# files > short_link sub-commands
|
|
917
944
|
register_short_link_commands(self, %i[files short_link])
|
|
918
945
|
|
|
919
946
|
# automation sub-commands
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
947
|
+
# Automation API: a workflow has ordered steps (step_order), a step has ordered actions (action_order)
|
|
948
|
+
AUTOMATION_CRUD = {api: :@automation_api, body_component: Schema::Registry::AUTOMATION}.freeze
|
|
949
|
+
private_constant :AUTOMATION_CRUD
|
|
950
|
+
commands_under :automation do
|
|
925
951
|
commands_under :workflows do
|
|
926
|
-
crud_commands
|
|
952
|
+
crud_commands(**AUTOMATION_CRUD, entity: 'workflows', items_key: 'workflows', query_component: Schema::Registry::AUTOMATION)
|
|
927
953
|
command :launch, description: 'Launch a workflow',
|
|
928
|
-
arguments: [{name: :
|
|
929
|
-
action: ->(
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
954
|
+
arguments: [{name: :workflow_id, type: :identifier}],
|
|
955
|
+
action: ->(workflow_id:, **) { Result::SingleObject.new(@automation_api.create("workflows/#{workflow_id}/launch", {})) }
|
|
956
|
+
command :update_state, description: 'Update state of workflow',
|
|
957
|
+
arguments: [{name: :workflow_id, type: :identifier},
|
|
958
|
+
{name: :state, type: Hash, schema: Schema::Registry.req_body(Schema::Registry::AUTOMATION, 'workflows/{id}/update_state.put')}],
|
|
959
|
+
action: ->(workflow_id:, state:, **) { Result::SingleObject.new(@automation_api.update("workflows/#{workflow_id}/update_state", state)) }
|
|
960
|
+
command(
|
|
961
|
+
:cancel_instances, description: 'Cancel all jobs of workflow',
|
|
962
|
+
arguments: [{name: :workflow_id, type: :identifier}],
|
|
963
|
+
action: lambda do |workflow_id:, **|
|
|
964
|
+
@automation_api.update("workflows/#{workflow_id}/cancel_instances", {})
|
|
965
|
+
Result::Status.new('canceled')
|
|
935
966
|
end
|
|
936
|
-
|
|
967
|
+
)
|
|
968
|
+
command(
|
|
969
|
+
:delete_instances, description: 'Delete all jobs of workflow',
|
|
970
|
+
arguments: [{name: :workflow_id, type: :identifier}],
|
|
971
|
+
action: lambda do |workflow_id:, **|
|
|
972
|
+
@automation_api.delete("workflows/#{workflow_id}/delete_instances")
|
|
973
|
+
Result::Status.new('deleted')
|
|
974
|
+
end
|
|
975
|
+
)
|
|
976
|
+
command :action, description: 'Manage actions of workflow',
|
|
977
|
+
arguments: [{name: :workflow_id, type: :identifier}]
|
|
978
|
+
command :permissions, description: 'Manage permissions of workflow',
|
|
979
|
+
arguments: [{name: :workflow_id, type: :identifier}]
|
|
980
|
+
end
|
|
981
|
+
# workflow_id is resolved by the parent command
|
|
982
|
+
commands_under %i[workflows action] do
|
|
983
|
+
command :list, description: 'List actions of all steps of workflow'
|
|
984
|
+
command :create, description: 'Add a step with one action at the end of workflow',
|
|
985
|
+
arguments: [{name: :action, type: Hash, mandatory: false, default: {}, schema: Schema::Registry.req_body(Schema::Registry::AUTOMATION, 'actions.post')}]
|
|
986
|
+
end
|
|
987
|
+
commands_under %i[workflows permissions] do
|
|
988
|
+
# API requires query parameter workflow_id
|
|
989
|
+
command(
|
|
990
|
+
:list, description: 'List permissions of workflow',
|
|
991
|
+
query_schema: Schema::Registry.query_params(Schema::Registry::AUTOMATION, 'workflow_permissions'),
|
|
992
|
+
action: lambda do |workflow_id:, **|
|
|
993
|
+
schema = Schema::Registry.query_params(Schema::Registry::AUTOMATION, 'workflow_permissions')
|
|
994
|
+
query = (query_read_delete(schema: schema) || {}).merge('workflow_id' => workflow_id)
|
|
995
|
+
Result::ObjectList.new(@automation_api.read('workflow_permissions', query))
|
|
996
|
+
end
|
|
997
|
+
)
|
|
998
|
+
command(
|
|
999
|
+
:create, description: 'Create a permission on workflow',
|
|
1000
|
+
arguments: [{name: :workflow_permission, type: Hash, bulk: true, schema: Schema::Registry.req_body(Schema::Registry::AUTOMATION, 'workflow_permissions.post')}],
|
|
1001
|
+
action: lambda do |workflow_id:, workflow_permission:, **|
|
|
1002
|
+
bulk_result(workflow_permission, command: :create) do |params|
|
|
1003
|
+
@automation_api.create('workflow_permissions', params.merge('workflow_id' => workflow_id))
|
|
1004
|
+
end
|
|
1005
|
+
end
|
|
1006
|
+
)
|
|
1007
|
+
crud_commands(**AUTOMATION_CRUD, entity: 'workflow_permissions', name: 'workflow permission', operations: %i[modify delete])
|
|
1008
|
+
end
|
|
1009
|
+
commands_under :instances do
|
|
1010
|
+
crud_commands(
|
|
1011
|
+
**AUTOMATION_CRUD, entity: 'workflow_instances', name: 'workflow instance', operations: %i[list show delete],
|
|
1012
|
+
items_key: 'workflow_instances', query_component: Schema::Registry::AUTOMATION
|
|
1013
|
+
)
|
|
1014
|
+
command :cancel, description: 'Cancel workflow instance',
|
|
1015
|
+
arguments: [{name: :workflow_instance_id, type: :identifier}],
|
|
1016
|
+
action: ->(workflow_instance_id:, **) { Result::SingleObject.new(@automation_api.update("workflow_instances/#{workflow_instance_id}", {'status' => 'canceled'})) }
|
|
1017
|
+
end
|
|
1018
|
+
commands_under :steps do
|
|
1019
|
+
crud_commands(**AUTOMATION_CRUD, entity: 'steps', operations: %i[create show modify delete])
|
|
1020
|
+
end
|
|
1021
|
+
commands_under :actions do
|
|
1022
|
+
crud_commands(**AUTOMATION_CRUD, entity: 'actions', operations: %i[create show modify delete])
|
|
937
1023
|
end
|
|
938
1024
|
end
|
|
939
1025
|
|
|
@@ -954,13 +1040,13 @@ module Aspera
|
|
|
954
1040
|
def setup_automation_api(**)
|
|
955
1041
|
change_api_scope(Api::AoC::Scope::ADMIN_USER)
|
|
956
1042
|
Log.log.warn('BETA: work under progress')
|
|
957
|
-
@automation_api = Rest.new(**aoc_api.params, base_url: aoc_api.base_url.gsub('/api/', '/automation/'))
|
|
1043
|
+
@automation_api = Rest::Client.new(**aoc_api.params, base_url: aoc_api.base_url.gsub('/api/', '/automation/'))
|
|
958
1044
|
{}
|
|
959
1045
|
end
|
|
960
1046
|
|
|
961
1047
|
# --- handler methods ---
|
|
962
1048
|
|
|
963
|
-
def action_reminder
|
|
1049
|
+
def action_reminder(**)
|
|
964
1050
|
user_email = options.get_option(:username, mandatory: true)
|
|
965
1051
|
no_auth_api = Api::AoC.new(url: options.get_option(:url), auth: :none)
|
|
966
1052
|
no_auth_api.create('organization_reminders', {email: user_email})
|
|
@@ -968,8 +1054,8 @@ module Aspera
|
|
|
968
1054
|
end
|
|
969
1055
|
|
|
970
1056
|
# packages > send
|
|
971
|
-
def action_packages_send(
|
|
972
|
-
package_data =
|
|
1057
|
+
def action_packages_send(package:, **)
|
|
1058
|
+
package_data = package
|
|
973
1059
|
new_user_option = options.get_option(:new_user_option)
|
|
974
1060
|
option_validate = options.get_option(:validate_metadata)
|
|
975
1061
|
workspace_id_hash(package_data, string: true) unless package_data.key?('workspace_id')
|
|
@@ -1042,7 +1128,7 @@ module Aspera
|
|
|
1042
1128
|
end
|
|
1043
1129
|
|
|
1044
1130
|
# packages > list
|
|
1045
|
-
def action_packages_list
|
|
1131
|
+
def action_packages_list(**)
|
|
1046
1132
|
result, max_items = list_all_packages_with_query
|
|
1047
1133
|
skip_ids_persistency = package_persistency
|
|
1048
1134
|
reject_packages_from_persistency(result[:items], skip_ids_persistency)
|
|
@@ -1052,11 +1138,6 @@ module Aspera
|
|
|
1052
1138
|
Result::ObjectList.new(result[:items], fields: display_fields, total: result[:total])
|
|
1053
1139
|
end
|
|
1054
1140
|
|
|
1055
|
-
# packages > show
|
|
1056
|
-
def action_packages_show(package_id:, **)
|
|
1057
|
-
Result::SingleObject.new(aoc_api.read("packages/#{package_id}"))
|
|
1058
|
-
end
|
|
1059
|
-
|
|
1060
1141
|
# packages > delete
|
|
1061
1142
|
def action_packages_delete(package_id:, **)
|
|
1062
1143
|
bulk_result(package_id, command: :delete) do |one_id|
|
|
@@ -1065,30 +1146,24 @@ module Aspera
|
|
|
1065
1146
|
end
|
|
1066
1147
|
end
|
|
1067
1148
|
|
|
1068
|
-
# packages
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
# (NODE4_READ_ACTIONS dispatched by full path: action_packages_bearer_token_node, etc.)
|
|
1076
|
-
Node::NODE4_READ_ACTIONS.each do |action|
|
|
1077
|
-
define_action_method([:packages, action]) do |package_id:, **|
|
|
1078
|
-
package_info = aoc_api.read("packages/#{package_id}")
|
|
1079
|
-
execute_nodegen4_command(action, package_info['node_id'], file_id: package_info['contents_file_id'], scope: Api::Node::Scope::USER)
|
|
1080
|
-
end
|
|
1149
|
+
# Used as `instance:` of the mount on packages: node of the package contents
|
|
1150
|
+
# @return [Array(Node, Hash)]
|
|
1151
|
+
def package_node_plugin(package_id:, **)
|
|
1152
|
+
package_info = aoc_api.read("packages/#{package_id}")
|
|
1153
|
+
# An id that is not a single path segment (e.g. `/`) reads the list of packages
|
|
1154
|
+
Aspera.assert(package_info.is_a?(Hash), type: Cli::BadArgument) { "invalid package id: #{package_id}" }
|
|
1155
|
+
nodegen4_plugin(package_info['node_id'], file_id: package_info['contents_file_id'], scope: Api::Node::Scope::USER)
|
|
1081
1156
|
end
|
|
1082
1157
|
|
|
1083
1158
|
# setup: files > short_link
|
|
1084
1159
|
# Resolves the target folder, consumes link_type argument, computes purposes.
|
|
1085
1160
|
# @return [Hash] ctx keys: sl_shared_data, sl_link_type, sl_token_purpose, sl_short_link_purpose, sl_perm_block, sl_shared_apifid, sl_folder_dest
|
|
1086
|
-
def setup_files_short_link(
|
|
1161
|
+
def setup_files_short_link(folder:, link_type:, **)
|
|
1087
1162
|
home_node_api = aoc_api.node_api_from(
|
|
1088
1163
|
node_id: aoc_api.home[:node_id],
|
|
1089
1164
|
**workspace_id_hash(name: true)
|
|
1090
1165
|
)
|
|
1091
|
-
shared_apifid = home_node_api.resolve_api_fid(aoc_api.home[:file_id],
|
|
1166
|
+
shared_apifid = home_node_api.resolve_api_fid(aoc_api.home[:file_id], folder)
|
|
1092
1167
|
shared_data = {
|
|
1093
1168
|
node_id: shared_apifid.node_api.app_info.node_info['id'],
|
|
1094
1169
|
file_id: shared_apifid.file_id
|
|
@@ -1104,7 +1179,7 @@ module Aspera
|
|
|
1104
1179
|
'access_levels' => Api::AoC.expand_access_levels(access_levels),
|
|
1105
1180
|
'tags' => {
|
|
1106
1181
|
'url_token' => true,
|
|
1107
|
-
'folder_name' => File.basename(
|
|
1182
|
+
'folder_name' => File.basename(folder),
|
|
1108
1183
|
'created_by_name' => aoc_api.current_user_info['name'],
|
|
1109
1184
|
'created_by_email' => aoc_api.current_user_info['email'],
|
|
1110
1185
|
'access_key' => shared_apifid.node_api.app_info.node_info['access_key'],
|
|
@@ -1135,10 +1210,9 @@ module Aspera
|
|
|
1135
1210
|
end
|
|
1136
1211
|
|
|
1137
1212
|
# setup: packages > shared_inboxes > short_link
|
|
1138
|
-
#
|
|
1213
|
+
# link_type: and dropbox_id: resolved via arguments: on the node, computes purposes.
|
|
1139
1214
|
# @return [Hash] ctx keys: sl_shared_data, sl_link_type, sl_token_purpose, sl_short_link_purpose
|
|
1140
|
-
def setup_packages_short_link(link_type:, **)
|
|
1141
|
-
dropbox_id = get_resource_id_from_args('dropboxes')
|
|
1215
|
+
def setup_packages_short_link(link_type:, dropbox_id:, **)
|
|
1142
1216
|
shared_data = {dropbox_id: dropbox_id, name: ''}
|
|
1143
1217
|
token_purpose, short_link_purpose = short_link_purposes(shared_data, link_type)
|
|
1144
1218
|
{
|
|
@@ -1167,7 +1241,7 @@ module Aspera
|
|
|
1167
1241
|
url_token_data: {data: shared_data, purpose: sl_token_purpose}
|
|
1168
1242
|
}
|
|
1169
1243
|
end
|
|
1170
|
-
custom_data =
|
|
1244
|
+
custom_data = custom_data.dup
|
|
1171
1245
|
access_levels = custom_data.delete('access_levels')
|
|
1172
1246
|
if (pass = custom_data.delete('password'))
|
|
1173
1247
|
create_payload[:data][:url_token_data][:password] = pass
|
|
@@ -1224,7 +1298,7 @@ module Aspera
|
|
|
1224
1298
|
one_id = short_link_id
|
|
1225
1299
|
node_file = sl_shared_data.slice(:node_id, :file_id)
|
|
1226
1300
|
modify_payload = {edit_access: true, json_query: node_file}
|
|
1227
|
-
custom_data =
|
|
1301
|
+
custom_data = custom_data.dup
|
|
1228
1302
|
if (pass = custom_data.delete('password'))
|
|
1229
1303
|
modify_payload[:password_enabled] = true
|
|
1230
1304
|
modify_payload[:data] = {url_token_data: {password: pass, data: node_file}}
|
|
@@ -1241,38 +1315,41 @@ module Aspera
|
|
|
1241
1315
|
Result::Status.new('modified')
|
|
1242
1316
|
end
|
|
1243
1317
|
|
|
1244
|
-
# files
|
|
1245
|
-
def
|
|
1246
|
-
|
|
1247
|
-
:transfer, aoc_api.home[:node_id],
|
|
1248
|
-
file_id: aoc_api.home[:file_id],
|
|
1249
|
-
scope: Api::Node::Scope::USER,
|
|
1250
|
-
transfer_direction: direction,
|
|
1251
|
-
transfer_source: source_folder
|
|
1252
|
-
)
|
|
1253
|
-
end
|
|
1254
|
-
|
|
1255
|
-
# files > FILES_COMMANDS (all Gen4 node commands except :transfer, handled above)
|
|
1256
|
-
FILES_COMMANDS.reject { |a| a.eql?(:transfer) }.each do |action|
|
|
1257
|
-
define_action_method([:files, action]) do |**ctx|
|
|
1258
|
-
execute_nodegen4_command(action, aoc_api.home[:node_id], file_id: aoc_api.home[:file_id], scope: Api::Node::Scope::USER, **ctx)
|
|
1259
|
-
end
|
|
1318
|
+
# files - mount target: Gen4 commands on the user's home folder
|
|
1319
|
+
def files_node_plugin(**)
|
|
1320
|
+
nodegen4_plugin(aoc_api.home[:node_id], file_id: aoc_api.home[:file_id], scope: Api::Node::Scope::USER)
|
|
1260
1321
|
end
|
|
1261
1322
|
|
|
1262
1323
|
# admin > application > instance > <type> > show|modify
|
|
1263
1324
|
APP_TYPES.each do |app_type|
|
|
1264
1325
|
define_action_method([:admin, :application, :instance, app_type, :show]) do |**kwargs|
|
|
1265
|
-
app_id = kwargs[:
|
|
1326
|
+
app_id = kwargs[:instance_id]
|
|
1266
1327
|
Result::SingleObject.new(aoc_api.read("admin/apps_new/#{app_type}/#{app_id}", query_read_delete))
|
|
1267
1328
|
end
|
|
1268
1329
|
|
|
1269
|
-
define_action_method([:admin, :application, :instance, app_type, :modify]) do |
|
|
1270
|
-
app_id = kwargs[:
|
|
1271
|
-
aoc_api.update("admin/apps_new/#{app_type}/#{app_id}",
|
|
1330
|
+
define_action_method([:admin, :application, :instance, app_type, :modify]) do |instance:, **kwargs|
|
|
1331
|
+
app_id = kwargs[:instance_id]
|
|
1332
|
+
aoc_api.update("admin/apps_new/#{app_type}/#{app_id}", instance)
|
|
1272
1333
|
Result::Status.new('modified')
|
|
1273
1334
|
end
|
|
1274
1335
|
end
|
|
1275
1336
|
|
|
1337
|
+
def action_admin_application_instance_list(**)
|
|
1338
|
+
result_list(
|
|
1339
|
+
'admin/apps_new',
|
|
1340
|
+
fields: %w[id app_type available workspace_id],
|
|
1341
|
+
default_query: {workspace_id: aoc_api.workspace_info[:id]}
|
|
1342
|
+
)
|
|
1343
|
+
end
|
|
1344
|
+
|
|
1345
|
+
def action_packages_shared_inboxes_list(**)
|
|
1346
|
+
result_list(
|
|
1347
|
+
'dropbox_memberships',
|
|
1348
|
+
fields: %w[dropbox_id dropbox.name],
|
|
1349
|
+
default_query: workspace_id_hash({'embed[]' => 'dropbox', 'aggregate_permissions_by_dropbox' => true, 'sort' => 'dropbox_name'}, string: true)
|
|
1350
|
+
)
|
|
1351
|
+
end
|
|
1352
|
+
|
|
1276
1353
|
def action_admin_application_membership_create(membership:, **)
|
|
1277
1354
|
data = membership.dup
|
|
1278
1355
|
app_type = data.delete('app_type')
|
|
@@ -1281,29 +1358,12 @@ module Aspera
|
|
|
1281
1358
|
Result::SingleObject.new(aoc_api.create("apps/#{app_type}/app_memberships", data))
|
|
1282
1359
|
end
|
|
1283
1360
|
|
|
1284
|
-
# admin > application > membership > show|delete
|
|
1285
|
-
def action_admin_application_membership_show(membership_id:, **)
|
|
1286
|
-
Result::SingleObject.new(aoc_api.read("apps/app_memberships/#{membership_id}", query_read_delete))
|
|
1287
|
-
end
|
|
1288
|
-
|
|
1289
|
-
def action_admin_application_membership_delete(membership_id:, **)
|
|
1290
|
-
aoc_api.delete("apps/app_memberships/#{membership_id}")
|
|
1291
|
-
Result::Status.new('deleted')
|
|
1292
|
-
end
|
|
1293
|
-
|
|
1294
1361
|
# admin - setup: change API scope to admin once
|
|
1295
1362
|
def setup_admin_scope(**)
|
|
1296
1363
|
change_api_scope(Api::AoC::Scope::ADMIN)
|
|
1297
1364
|
{}
|
|
1298
1365
|
end
|
|
1299
1366
|
|
|
1300
|
-
# admin > subscription > account
|
|
1301
|
-
def action_admin_subscription_account
|
|
1302
|
-
org = aoc_api.read('organization')
|
|
1303
|
-
result = GraphQL.execute(api_from_options('bss/platform/graphql'), 'bss_subscription_account', {organization_id: org['id']})
|
|
1304
|
-
Result::SingleObject.new(result['aoc']['bssSubscription'])
|
|
1305
|
-
end
|
|
1306
|
-
|
|
1307
1367
|
# admin > subscription > usage
|
|
1308
1368
|
def action_admin_subscription_usage(aggregate:, start_date:, end_date:, **)
|
|
1309
1369
|
today = Date.today
|
|
@@ -1318,21 +1378,20 @@ module Aspera
|
|
|
1318
1378
|
Result::SingleObject.new(result['aoc'])
|
|
1319
1379
|
end
|
|
1320
1380
|
|
|
1321
|
-
#
|
|
1322
|
-
def
|
|
1323
|
-
|
|
1324
|
-
|
|
1381
|
+
# @return [String] the given resource id, or the one of the current user if empty
|
|
1382
|
+
def analytics_resource_id(event_resource_type, event_resource_id)
|
|
1383
|
+
return event_resource_id unless event_resource_id.to_s.empty?
|
|
1384
|
+
case event_resource_type
|
|
1385
|
+
when :organizations then aoc_api.current_user_info['organization_id']
|
|
1386
|
+
when :users then aoc_api.current_user_info['id']
|
|
1387
|
+
when :nodes then aoc_api.current_user_info['read_only_home_node_id']
|
|
1388
|
+
else Aspera.error_unreachable_line
|
|
1389
|
+
end
|
|
1325
1390
|
end
|
|
1326
1391
|
|
|
1327
1392
|
# admin > analytics > transfers
|
|
1328
1393
|
def action_admin_analytics_transfers(event_resource_type:, event_resource_id:, **)
|
|
1329
|
-
event_resource_id
|
|
1330
|
-
case event_resource_type
|
|
1331
|
-
when :organizations then aoc_api.current_user_info['organization_id']
|
|
1332
|
-
when :users then aoc_api.current_user_info['id']
|
|
1333
|
-
when :nodes then aoc_api.current_user_info['read_only_home_node_id']
|
|
1334
|
-
else Aspera.error_unreachable_line
|
|
1335
|
-
end
|
|
1394
|
+
event_resource_id = analytics_resource_id(event_resource_type, event_resource_id)
|
|
1336
1395
|
filter = query_read_delete(default: {})
|
|
1337
1396
|
filter['limit'] ||= 100
|
|
1338
1397
|
if options.get_option(:once_only, mandatory: true)
|
|
@@ -1356,13 +1415,7 @@ module Aspera
|
|
|
1356
1415
|
|
|
1357
1416
|
# admin > analytics > files
|
|
1358
1417
|
def action_admin_analytics_files(event_resource_type:, event_resource_id:, event_uuid:, **)
|
|
1359
|
-
event_resource_id =
|
|
1360
|
-
case event_resource_type
|
|
1361
|
-
when :organizations then aoc_api.current_user_info['organization_id']
|
|
1362
|
-
when :users then aoc_api.current_user_info['id']
|
|
1363
|
-
when :nodes then aoc_api.current_user_info['read_only_home_node_id']
|
|
1364
|
-
else Aspera.error_unreachable_line
|
|
1365
|
-
end if event_resource_id.to_s.empty?
|
|
1418
|
+
event_resource_id = analytics_resource_id(event_resource_type, event_resource_id)
|
|
1366
1419
|
filter = query_read_delete(default: {})
|
|
1367
1420
|
filter['limit'] ||= 100
|
|
1368
1421
|
events = build_analytics_api.read("#{event_resource_type}/#{event_resource_id}/transfers/#{event_uuid}/files", filter)['files']
|
|
@@ -1370,7 +1423,7 @@ module Aspera
|
|
|
1370
1423
|
end
|
|
1371
1424
|
|
|
1372
1425
|
# Lookup methods for arguments:(:identifier) + lookup: on admin resources.
|
|
1373
|
-
# One method per non-singleton resource
|
|
1426
|
+
# One method per non-singleton resource: percent selector searches with `q=<value>`.
|
|
1374
1427
|
ADMIN_OBJECTS.reject { |r| ADMIN_OBJECT_CONFIG.dig(r, :singleton) }.each do |res|
|
|
1375
1428
|
define_method(:"lookup_aoc_#{res}_id") do |_field, value, **|
|
|
1376
1429
|
aoc_api.lookup_with_q(aoc_res_path(res), value: value)['id']
|
|
@@ -1379,7 +1432,7 @@ module Aspera
|
|
|
1379
1432
|
|
|
1380
1433
|
# admin > <res> > list
|
|
1381
1434
|
ADMIN_OBJECTS.each do |res|
|
|
1382
|
-
define_action_method([:admin, res, :list]) do
|
|
1435
|
+
define_action_method([:admin, res, :list]) do |**|
|
|
1383
1436
|
c = aoc_res_cfg(res)
|
|
1384
1437
|
result_list(c[:path], fields: c[:list_fields], query_component: c[:query_component])
|
|
1385
1438
|
end
|
|
@@ -1396,14 +1449,15 @@ module Aspera
|
|
|
1396
1449
|
|
|
1397
1450
|
# admin > organization|self > show (singleton)
|
|
1398
1451
|
%i[organization self].each do |res|
|
|
1399
|
-
define_action_method([:admin, res, :show]) do
|
|
1452
|
+
define_action_method([:admin, res, :show]) do |**|
|
|
1400
1453
|
Result::SingleObject.new(aoc_api.read(res.to_s, query_read_delete), fields: Formatter.all_but('certificate'))
|
|
1401
1454
|
end
|
|
1402
1455
|
end
|
|
1403
1456
|
|
|
1404
1457
|
# admin > <res> > create
|
|
1405
1458
|
ADMIN_OBJECTS.reject { |r| ADMIN_OBJECT_CONFIG.dig(r, :singleton) }.each do |res|
|
|
1406
|
-
define_action_method([:admin, res, :create]) do |
|
|
1459
|
+
define_action_method([:admin, res, :create]) do |**kwargs|
|
|
1460
|
+
data = kwargs.fetch(res)
|
|
1407
1461
|
c = aoc_res_cfg(res)
|
|
1408
1462
|
path = c[:path]
|
|
1409
1463
|
# Special case: client_registration_token has a different creation URL
|
|
@@ -1418,7 +1472,8 @@ module Aspera
|
|
|
1418
1472
|
|
|
1419
1473
|
# admin > <res> > modify
|
|
1420
1474
|
ADMIN_OBJECTS.reject { |r| ADMIN_OBJECT_CONFIG.dig(r, :singleton) || ADMIN_OBJECT_CONFIG.dig(r, :ops)&.then { |o| !o.include?(:modify) } }.each do |res|
|
|
1421
|
-
define_action_method([:admin, res, :modify]) do
|
|
1475
|
+
define_action_method([:admin, res, :modify]) do |**kwargs|
|
|
1476
|
+
data = kwargs.fetch(res)
|
|
1422
1477
|
res_id = kwargs[:"#{res}_id"]
|
|
1423
1478
|
c = aoc_res_cfg(res)
|
|
1424
1479
|
aoc_api.update("#{c[:path]}/#{res_id}", data)
|
|
@@ -1448,6 +1503,28 @@ module Aspera
|
|
|
1448
1503
|
end
|
|
1449
1504
|
end
|
|
1450
1505
|
|
|
1506
|
+
# automation > workflows > action > list
|
|
1507
|
+
# A workflow has ordered steps (step_order), a step has ordered actions (action_order)
|
|
1508
|
+
def action_automation_workflows_action_list(workflow_id:, **)
|
|
1509
|
+
workflow = @automation_api.read("workflows/#{workflow_id}")
|
|
1510
|
+
actions = Array(workflow['step_order']).flat_map do |step_id|
|
|
1511
|
+
step = @automation_api.read("steps/#{step_id}")
|
|
1512
|
+
Array(step['action_order']).map { |action_id| @automation_api.read("actions/#{action_id}") }
|
|
1513
|
+
end
|
|
1514
|
+
Result::ObjectList.new(actions)
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
# automation > workflows > action > create
|
|
1518
|
+
# Default action type is `manual`
|
|
1519
|
+
def action_automation_workflows_action_create(workflow_id:, action:, **)
|
|
1520
|
+
workflow = @automation_api.read("workflows/#{workflow_id}")
|
|
1521
|
+
step = @automation_api.create('steps', {'workflow_id' => workflow_id})
|
|
1522
|
+
@automation_api.update("workflows/#{workflow_id}", {'step_order' => Array(workflow['step_order']) + [step['id']]})
|
|
1523
|
+
new_action = @automation_api.create('actions', {'type' => 'manual'}.merge(action).merge('step_id' => step['id']))
|
|
1524
|
+
@automation_api.update("steps/#{step['id']}", {'action_order' => [new_action['id']]})
|
|
1525
|
+
Result::SingleObject.new(new_action)
|
|
1526
|
+
end
|
|
1527
|
+
|
|
1451
1528
|
# admin > client > set_pub_key
|
|
1452
1529
|
def action_admin_client_set_pub_key(private_key_pem:, client_id:, **)
|
|
1453
1530
|
c = aoc_res_cfg(:client)
|
|
@@ -1457,10 +1534,10 @@ module Aspera
|
|
|
1457
1534
|
end
|
|
1458
1535
|
|
|
1459
1536
|
# admin > ats — build and return an Ats plugin instance wired to the AoC ATS API.
|
|
1460
|
-
#
|
|
1537
|
+
# Mount target of `admin ats`.
|
|
1461
1538
|
# @return [Ats] configured Ats plugin instance
|
|
1462
|
-
def build_ats_plugin
|
|
1463
|
-
ats_api = Rest.new(**aoc_api.params.deep_merge({
|
|
1539
|
+
def build_ats_plugin(**)
|
|
1540
|
+
ats_api = Rest::Client.new(**aoc_api.params.deep_merge({
|
|
1464
1541
|
base_url: "#{aoc_api.base_url}/admin/ats/pub/v1",
|
|
1465
1542
|
auth: {params: {scope: Api::AoC::Scope::ADMIN_USER}}
|
|
1466
1543
|
}))
|
|
@@ -1470,11 +1547,9 @@ module Aspera
|
|
|
1470
1547
|
# admin > node > do | bearer_token — setup reuses the generic instance setup
|
|
1471
1548
|
# (setup_admin_node_instance is auto-generated above, providing res_id:)
|
|
1472
1549
|
|
|
1473
|
-
# admin > node > do
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
execute_nodegen4_command(cmd, node_id, scope: Api::Node::Scope::ADMIN, **ctx)
|
|
1477
|
-
end
|
|
1550
|
+
# admin > node > do - mount target: Gen4 commands on the node, admin scope
|
|
1551
|
+
def admin_node_do_plugin(node_id:, **)
|
|
1552
|
+
nodegen4_plugin(node_id, scope: Api::Node::Scope::ADMIN)
|
|
1478
1553
|
end
|
|
1479
1554
|
|
|
1480
1555
|
# admin > node > bearer_token
|
|
@@ -1494,28 +1569,17 @@ module Aspera
|
|
|
1494
1569
|
{ws_res_id: workspace_id}
|
|
1495
1570
|
end
|
|
1496
1571
|
|
|
1497
|
-
# admin > workspace > dropbox > list
|
|
1498
|
-
def action_admin_workspace_dropbox_list(ws_res_id:, **)
|
|
1499
|
-
query = options.get_option(:query) || {}
|
|
1500
|
-
Result::ObjectList.new(aoc_api.read('dropboxes', query.merge({'workspace_id' => ws_res_id})), fields: %w[id name description])
|
|
1501
|
-
end
|
|
1502
|
-
|
|
1503
1572
|
# admin > workspace > shared_folder — res_id: already in ctx via arguments:(:identifier)
|
|
1504
1573
|
def setup_admin_workspace_shared_folder(workspace_id:, **)
|
|
1505
1574
|
resource_instance_path = "#{aoc_res_path(:workspace)}/#{workspace_id}"
|
|
1506
|
-
query =
|
|
1575
|
+
query = query_read_delete(default: Api::AoC.workspace_access(workspace_id).merge({'admin' => true}))
|
|
1507
1576
|
shared_folders = aoc_api.read_with_paging("#{resource_instance_path}/permissions", query)[:items]
|
|
1508
1577
|
{ws_res_id: workspace_id, shared_folders: shared_folders}
|
|
1509
1578
|
end
|
|
1510
1579
|
|
|
1511
|
-
# admin > workspace > shared_folder >
|
|
1512
|
-
def
|
|
1513
|
-
|
|
1514
|
-
end
|
|
1515
|
-
|
|
1516
|
-
# admin > workspace > shared_folder > node|member — sf_id: already in ctx via arguments:(:identifier)
|
|
1517
|
-
def resolve_sf_item(shared_folders:, sf_id:, **)
|
|
1518
|
-
sf_item = shared_folders.find { |i| i['id'].eql?(sf_id) }
|
|
1580
|
+
# admin > workspace > shared_folder > node|member — shared_folder_id: already in ctx via arguments:(:identifier)
|
|
1581
|
+
def resolve_sf_item(shared_folders:, shared_folder_id:, **)
|
|
1582
|
+
sf_item = shared_folders.find { |i| i['id'].eql?(shared_folder_id) }
|
|
1519
1583
|
Aspera.assert(sf_item, 'shared folder not found')
|
|
1520
1584
|
{sf_item: sf_item}
|
|
1521
1585
|
end
|
|
@@ -1523,11 +1587,9 @@ module Aspera
|
|
|
1523
1587
|
alias_method :setup_admin_workspace_shared_folder_node, :resolve_sf_item
|
|
1524
1588
|
alias_method :setup_admin_workspace_shared_folder_member, :resolve_sf_item
|
|
1525
1589
|
|
|
1526
|
-
# admin > workspace > shared_folder > node
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
execute_nodegen4_command(cmd, sf_item['node_id'], file_id: sf_item['file_id'], scope: Api::Node::Scope::ADMIN, **ctx)
|
|
1530
|
-
end
|
|
1590
|
+
# admin > workspace > shared_folder > node - mount target: Gen4 commands on the shared folder, admin scope
|
|
1591
|
+
def admin_workspace_shared_folder_node_plugin(sf_item:, **)
|
|
1592
|
+
nodegen4_plugin(sf_item['node_id'], file_id: sf_item['file_id'], scope: Api::Node::Scope::ADMIN)
|
|
1531
1593
|
end
|
|
1532
1594
|
|
|
1533
1595
|
# admin > workspace > shared_folder > member > list
|
|
@@ -1561,24 +1623,12 @@ module Aspera
|
|
|
1561
1623
|
define_action_method([:admin, :user, pref, :show]) do |user_id:, **|
|
|
1562
1624
|
Result::SingleObject.new(aoc_api.read("#{aoc_res_path(:user)}/#{user_id}/#{pref_path}"))
|
|
1563
1625
|
end
|
|
1564
|
-
define_action_method([:admin, :user, pref, :modify]) do |
|
|
1565
|
-
aoc_api.update("#{aoc_res_path(:user)}/#{user_id}/#{pref_path}",
|
|
1626
|
+
define_action_method([:admin, :user, pref, :modify]) do |user_id:, **kwargs|
|
|
1627
|
+
aoc_api.update("#{aoc_res_path(:user)}/#{user_id}/#{pref_path}", kwargs.fetch(pref))
|
|
1566
1628
|
Result::Status.new('modified')
|
|
1567
1629
|
end
|
|
1568
1630
|
end
|
|
1569
1631
|
|
|
1570
|
-
# automation > workflows > action > * (TODO: not fully implemented)
|
|
1571
|
-
%i[list create show].each do |cmd|
|
|
1572
|
-
define_action_method([:automation, :workflows, :action, cmd]) do |wf_id:, **|
|
|
1573
|
-
Log.log.warn { "Not implemented: #{cmd}" }
|
|
1574
|
-
step = @automation_api.create('steps', {'workflow_id' => wf_id})
|
|
1575
|
-
@automation_api.update("workflows/#{wf_id}", {'step_order' => [step['id']]})
|
|
1576
|
-
action = @automation_api.create('actions', {'step_id' => step['id'], 'type' => 'manual'})
|
|
1577
|
-
@automation_api.update("steps/#{step['id']}", {'action_order' => [action['id']]})
|
|
1578
|
-
Result::SingleObject.new(@automation_api.read("workflows/#{wf_id}"))
|
|
1579
|
-
end
|
|
1580
|
-
end
|
|
1581
|
-
|
|
1582
1632
|
def action_gateway(parameters: {}, **)
|
|
1583
1633
|
require 'aspera/faspex_gw'
|
|
1584
1634
|
parameters = parameters.symbolize_keys
|