aspera-cli 4.14.0 → 4.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +29 -3
- data/CHANGELOG.md +300 -185
- data/CONTRIBUTING.md +74 -23
- data/README.md +2346 -1619
- data/bin/ascli +16 -25
- data/bin/asession +15 -15
- data/examples/dascli +2 -2
- data/examples/proxy.pac +1 -1
- data/lib/aspera/aoc.rb +216 -150
- data/lib/aspera/ascmd.rb +25 -18
- data/lib/aspera/assert.rb +45 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +51 -16
- data/lib/aspera/cli/formatter.rb +276 -174
- data/lib/aspera/cli/hints.rb +81 -0
- data/lib/aspera/cli/main.rb +114 -147
- data/lib/aspera/cli/manager.rb +181 -136
- data/lib/aspera/cli/plugin.rb +82 -64
- data/lib/aspera/cli/plugins/alee.rb +0 -1
- data/lib/aspera/cli/plugins/aoc.rb +327 -331
- data/lib/aspera/cli/plugins/ats.rb +12 -8
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +575 -439
- data/lib/aspera/cli/plugins/console.rb +40 -0
- data/lib/aspera/cli/plugins/cos.rb +4 -5
- data/lib/aspera/cli/plugins/faspex.rb +111 -92
- data/lib/aspera/cli/plugins/faspex5.rb +245 -182
- data/lib/aspera/cli/plugins/node.rb +239 -160
- data/lib/aspera/cli/plugins/orchestrator.rb +56 -19
- data/lib/aspera/cli/plugins/preview.rb +54 -38
- data/lib/aspera/cli/plugins/server.rb +63 -20
- data/lib/aspera/cli/plugins/shares.rb +64 -38
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +64 -67
- data/lib/aspera/cli/transfer_progress.rb +73 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -1
- data/lib/aspera/command_line_builder.rb +27 -22
- data/lib/aspera/cos_node.rb +6 -4
- data/lib/aspera/coverage.rb +22 -0
- data/lib/aspera/data_repository.rb +33 -2
- data/lib/aspera/environment.rb +21 -8
- data/lib/aspera/fasp/agent_alpha.rb +116 -0
- data/lib/aspera/fasp/agent_base.rb +40 -76
- data/lib/aspera/fasp/agent_connect.rb +21 -22
- data/lib/aspera/fasp/agent_direct.rb +169 -179
- data/lib/aspera/fasp/agent_httpgw.rb +200 -195
- data/lib/aspera/fasp/agent_node.rb +43 -35
- data/lib/aspera/fasp/agent_trsdk.rb +124 -41
- data/lib/aspera/fasp/error_info.rb +2 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +89 -191
- data/lib/aspera/fasp/management.rb +249 -0
- data/lib/aspera/fasp/parameters.rb +86 -47
- data/lib/aspera/fasp/parameters.yaml +75 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/resume_policy.rb +7 -5
- data/lib/aspera/fasp/sync.rb +273 -0
- data/lib/aspera/fasp/transfer_spec.rb +10 -8
- data/lib/aspera/fasp/uri.rb +6 -6
- data/lib/aspera/faspex_gw.rb +11 -8
- data/lib/aspera/faspex_postproc.rb +8 -7
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/id_generator.rb +3 -1
- data/lib/aspera/json_rpc.rb +51 -0
- data/lib/aspera/keychain/encrypted_hash.rb +46 -11
- data/lib/aspera/keychain/macos_security.rb +15 -13
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +61 -19
- data/lib/aspera/nagios.rb +7 -2
- data/lib/aspera/node.rb +105 -21
- data/lib/aspera/node_simulator.rb +214 -0
- data/lib/aspera/oauth.rb +57 -36
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +13 -14
- data/lib/aspera/persistency_folder.rb +5 -4
- data/lib/aspera/preview/file_types.rb +56 -268
- data/lib/aspera/preview/generator.rb +28 -39
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +36 -16
- data/lib/aspera/preview/utils.rb +23 -29
- data/lib/aspera/proxy_auto_config.rb +6 -3
- data/lib/aspera/rest.rb +127 -80
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +16 -14
- data/lib/aspera/rest_errors_aspera.rb +39 -34
- data/lib/aspera/secret_hider.rb +18 -17
- data/lib/aspera/ssh.rb +10 -5
- data/lib/aspera/temp_file_manager.rb +11 -4
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +11 -5
- data.tar.gz.sig +0 -0
- metadata +108 -39
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/fasp/listener.rb +0 -13
- data/lib/aspera/sync.rb +0 -213
|
@@ -10,6 +10,7 @@ require 'aspera/aoc'
|
|
|
10
10
|
require 'aspera/node'
|
|
11
11
|
require 'aspera/persistency_action_once'
|
|
12
12
|
require 'aspera/id_generator'
|
|
13
|
+
require 'aspera/assert'
|
|
13
14
|
require 'securerandom'
|
|
14
15
|
require 'date'
|
|
15
16
|
|
|
@@ -17,18 +18,130 @@ module Aspera
|
|
|
17
18
|
module Cli
|
|
18
19
|
module Plugins
|
|
19
20
|
class Aoc < Aspera::Cli::BasicAuthPlugin
|
|
21
|
+
AOC_PATH_API_CLIENTS = 'admin/api-clients'
|
|
22
|
+
# default redirect for AoC web auth
|
|
23
|
+
DEFAULT_REDIRECT = 'http://localhost:12345'
|
|
24
|
+
private_constant :AOC_PATH_API_CLIENTS, :DEFAULT_REDIRECT
|
|
20
25
|
class << self
|
|
26
|
+
def application_name
|
|
27
|
+
'Aspera on Cloud'
|
|
28
|
+
end
|
|
29
|
+
|
|
21
30
|
def detect(base_url)
|
|
22
|
-
|
|
31
|
+
# no protocol ?
|
|
32
|
+
base_url = "https://#{base_url}" unless base_url.match?(%r{^[a-z]{1,6}://})
|
|
33
|
+
# only org provided ?
|
|
34
|
+
base_url = "#{base_url}.#{Aspera::AoC::PROD_DOMAIN}" unless base_url.include?('.')
|
|
35
|
+
# AoC is only https
|
|
36
|
+
return nil unless base_url.start_with?('https://')
|
|
37
|
+
result = Rest.new({base_url: base_url, redirect_max: 10}).read('')
|
|
38
|
+
# Any AoC is on this domain
|
|
39
|
+
return nil unless result[:http].uri.host.end_with?(Aspera::AoC::PROD_DOMAIN)
|
|
40
|
+
Log.log.debug{'AoC Main page: #{result[:http].body.include?(Aspera::AoC::PRODUCT_NAME)}'}
|
|
41
|
+
base_url = result[:http].uri.to_s if result[:http].uri.path.include?('/public')
|
|
23
42
|
# either in standard domain, or product name in page
|
|
24
|
-
|
|
25
|
-
|
|
43
|
+
return {
|
|
44
|
+
version: 'SaaS',
|
|
45
|
+
url: base_url
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def private_key_required?(url)
|
|
50
|
+
# pub link do not need private key
|
|
51
|
+
return AoC.link_info(url)[:token].nil?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @param [Hash] env : options, formatter
|
|
55
|
+
# @param [Hash] params : plugin_sym, instance_url
|
|
56
|
+
# @return [Hash] :preset_value, :test_args
|
|
57
|
+
def wizard(object:, private_key_path: nil, pub_key_pem: nil)
|
|
58
|
+
# set vars to look like object
|
|
59
|
+
options = object.options
|
|
60
|
+
formatter = object.formatter
|
|
61
|
+
options.declare(:use_generic_client, 'Wizard: AoC: use global or org specific jwt client id', values: :bool, default: true)
|
|
62
|
+
options.parse_options!
|
|
63
|
+
instance_url = options.get_option(:url, mandatory: true)
|
|
64
|
+
pub_link_info = AoC.link_info(instance_url)
|
|
65
|
+
if !pub_link_info[:token].nil?
|
|
66
|
+
pub_api = Rest.new({base_url: "https://#{URI.parse(pub_link_info[:url]).host}/api/v1"})
|
|
67
|
+
pub_info = pub_api.read('env/url_token_check', {token: pub_link_info[:token]})[:data]
|
|
68
|
+
preset_value = {
|
|
69
|
+
link: instance_url
|
|
70
|
+
}
|
|
71
|
+
preset_value[:password] = options.get_option(:password, mandatory: true) if pub_info['password_protected']
|
|
26
72
|
return {
|
|
27
|
-
|
|
28
|
-
|
|
73
|
+
preset_value: preset_value,
|
|
74
|
+
test_args: 'organization'
|
|
29
75
|
}
|
|
30
76
|
end
|
|
31
|
-
|
|
77
|
+
# make username mandatory for jwt, this triggers interactive input
|
|
78
|
+
wiz_username = options.get_option(:username, mandatory: true)
|
|
79
|
+
raise "Username shall be an email in AoC: #{wiz_username}" if !(wiz_username =~ /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i)
|
|
80
|
+
# Set the pub key and jwt tag in the user's profile automatically
|
|
81
|
+
auto_set_pub_key = false
|
|
82
|
+
auto_set_jwt = false
|
|
83
|
+
# use browser authentication to bootstrap
|
|
84
|
+
use_browser_authentication = false
|
|
85
|
+
if options.get_option(:use_generic_client)
|
|
86
|
+
formatter.display_status('Using global client_id.')
|
|
87
|
+
formatter.display_status('Please Login to your Aspera on Cloud instance.')
|
|
88
|
+
formatter.display_status('Navigate to: 👤 → Account Settings → Profile → Public Key')
|
|
89
|
+
formatter.display_status('Check or update the value to:'.red.blink)
|
|
90
|
+
formatter.display_status(pub_key_pem)
|
|
91
|
+
if !options.get_option(:test_mode)
|
|
92
|
+
formatter.display_status('Once updated or validated, press enter.')
|
|
93
|
+
OpenApplication.instance.uri(instance_url)
|
|
94
|
+
$stdin.gets
|
|
95
|
+
end
|
|
96
|
+
else
|
|
97
|
+
formatter.display_status('Using organization specific client_id.')
|
|
98
|
+
if options.get_option(:client_id).nil? || options.get_option(:client_secret).nil?
|
|
99
|
+
formatter.display_status('Please login to your Aspera on Cloud instance.'.red)
|
|
100
|
+
formatter.display_status('Navigate to: 𓃑 → Admin → Integrations → API Clients')
|
|
101
|
+
formatter.display_status('Check or create in integration:')
|
|
102
|
+
formatter.display_status("- name: #{@info[:name]}")
|
|
103
|
+
formatter.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
|
|
104
|
+
formatter.display_status('- origin: localhost')
|
|
105
|
+
formatter.display_status('Use the generated client id and secret in the following prompts.'.red)
|
|
106
|
+
end
|
|
107
|
+
OpenApplication.instance.uri("#{instance_url}/#{AOC_PATH_API_CLIENTS}")
|
|
108
|
+
options.get_option(:client_id, mandatory: true)
|
|
109
|
+
options.get_option(:client_secret, mandatory: true)
|
|
110
|
+
use_browser_authentication = true
|
|
111
|
+
end
|
|
112
|
+
if use_browser_authentication
|
|
113
|
+
formatter.display_status('We will use web authentication to bootstrap.')
|
|
114
|
+
auto_set_pub_key = true
|
|
115
|
+
auto_set_jwt = true
|
|
116
|
+
aoc_api.oauth.generic_parameters[:grant_method] = :web
|
|
117
|
+
aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
|
|
118
|
+
aoc_api.oauth.specific_parameters[:redirect_uri] = DEFAULT_REDIRECT
|
|
119
|
+
end
|
|
120
|
+
myself = object.aoc_api.read('self')[:data]
|
|
121
|
+
if auto_set_pub_key
|
|
122
|
+
assert(myself['public_key'].empty?, exception_class: Cli::Error){'Public key is already set in profile (use --override=yes)'} unless option_override
|
|
123
|
+
formatter.display_status('Updating profile with the public key.')
|
|
124
|
+
aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
|
|
125
|
+
end
|
|
126
|
+
if auto_set_jwt
|
|
127
|
+
formatter.display_status('Enabling JWT for client')
|
|
128
|
+
aoc_api.update("clients/#{options.get_option(:client_id)}", {'jwt_grant_enabled' => true, 'explicit_authorization_required' => false})
|
|
129
|
+
end
|
|
130
|
+
preset_result = {
|
|
131
|
+
url: instance_url,
|
|
132
|
+
username: myself['email'],
|
|
133
|
+
auth: :jwt.to_s,
|
|
134
|
+
private_key: "@file:#{private_key_path}"
|
|
135
|
+
}
|
|
136
|
+
# set only if non nil
|
|
137
|
+
%i[client_id client_secret].each do |s|
|
|
138
|
+
o = options.get_option(s)
|
|
139
|
+
preset_result[s.to_s] = o unless o.nil?
|
|
140
|
+
end
|
|
141
|
+
return {
|
|
142
|
+
preset_value: preset_result,
|
|
143
|
+
test_args: 'user profile show'
|
|
144
|
+
}
|
|
32
145
|
end
|
|
33
146
|
end
|
|
34
147
|
# special value for package id
|
|
@@ -53,9 +166,11 @@ module Aspera
|
|
|
53
166
|
client_registration_token
|
|
54
167
|
client_access_key
|
|
55
168
|
kms_profile].freeze
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
169
|
+
PACKAGE_RECEIVED_BASE_QUERY = {
|
|
170
|
+
'archived' => false,
|
|
171
|
+
'has_content' => true,
|
|
172
|
+
'received' => true,
|
|
173
|
+
'completed' => true}.freeze
|
|
59
174
|
|
|
60
175
|
def initialize(env)
|
|
61
176
|
super(env)
|
|
@@ -63,135 +178,60 @@ module Aspera
|
|
|
63
178
|
@cache_home_node_file = nil
|
|
64
179
|
@cache_api_aoc = nil
|
|
65
180
|
options.declare(:auth, 'OAuth type of authentication', values: Oauth::STD_AUTH_TYPES, default: :jwt)
|
|
66
|
-
options.declare(:operation, 'Client operation for transfers', values: %i[push pull], default: :push)
|
|
67
181
|
options.declare(:client_id, 'OAuth API client identifier')
|
|
68
182
|
options.declare(:client_secret, 'OAuth API client secret')
|
|
183
|
+
options.declare(:scope, 'OAuth scope for AoC API calls', default: AoC::SCOPE_FILES_USER)
|
|
69
184
|
options.declare(:redirect_uri, 'OAuth API client redirect URI')
|
|
70
185
|
options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
|
|
71
|
-
options.declare(:scope, 'OAuth scope for AoC API calls', default: AoC::SCOPE_FILES_USER)
|
|
72
186
|
options.declare(:passphrase, 'RSA private key passphrase')
|
|
73
|
-
options.declare(:workspace, 'Name of workspace', default:
|
|
74
|
-
# TODO: remove this and use %name: instead
|
|
75
|
-
options.declare(:name, "Resource name (prefer to use keyword #{ENTITY_NAME_SPECIFIER})")
|
|
76
|
-
options.declare(:link, 'Public link to shared resource')
|
|
187
|
+
options.declare(:workspace, 'Name of workspace', types: [String, NilClass], default: Aspera::AoC::DEFAULT_WORKSPACE)
|
|
77
188
|
options.declare(:new_user_option, 'New user creation option for unknown package recipients')
|
|
78
|
-
options.declare(:from_folder, 'Source folder for Folder-to-Folder transfer')
|
|
79
189
|
options.declare(:validate_metadata, 'Validate shared inbox metadata', values: :bool, default: true)
|
|
80
190
|
options.parse_options!
|
|
81
|
-
# add node plugin options (
|
|
82
|
-
Node.
|
|
191
|
+
# add node plugin options (for manual)
|
|
192
|
+
Node.declare_options(options)
|
|
83
193
|
end
|
|
84
194
|
|
|
85
|
-
|
|
86
|
-
def aoc_params(subpath)
|
|
87
|
-
# copy command line options to args
|
|
88
|
-
return Aspera::AoC::OPTIONS_NEW.each_with_object({subpath: subpath}){|i, m|m[i] = options.get_option(i)}
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def aoc_api
|
|
92
|
-
if @cache_api_aoc.nil?
|
|
93
|
-
@cache_api_aoc = AoC.new(aoc_params(AoC::API_V1))
|
|
94
|
-
# add keychain for access key secrets
|
|
95
|
-
@cache_api_aoc.secret_finder = @agents[:config]
|
|
96
|
-
end
|
|
97
|
-
return @cache_api_aoc
|
|
98
|
-
end
|
|
195
|
+
OPTIONS_NEW = %i[url auth client_id client_secret scope redirect_uri private_key passphrase username password workspace].freeze
|
|
99
196
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
197
|
+
def api_from_options(new_base_path)
|
|
198
|
+
create_values = {subpath: new_base_path, secret_finder: @agents[:config]}
|
|
199
|
+
# create an API object with the same options, but with a different subpath
|
|
200
|
+
return Aspera::AoC.new(**OPTIONS_NEW.each_with_object(create_values) { |i, m|m[i] = options.get_option(i) unless options.get_option(i).nil?})
|
|
201
|
+
rescue ArgumentError => e
|
|
202
|
+
if (m = e.message.match(/missing keyword: :(.*)$/))
|
|
203
|
+
raise Cli::Error, "Missing option: #{m[1]}"
|
|
107
204
|
end
|
|
108
|
-
|
|
109
|
-
ws_name = options.get_option(:workspace)
|
|
110
|
-
ws_id =
|
|
111
|
-
case ws_name
|
|
112
|
-
when :default
|
|
113
|
-
Log.log.debug('Using default workspace'.green)
|
|
114
|
-
raise CliError, 'No default workspace defined for user, please specify workspace' if default_workspace_id.nil?
|
|
115
|
-
default_workspace_id
|
|
116
|
-
when String then aoc_api.lookup_by_name('workspaces', ws_name)['id']
|
|
117
|
-
when NilClass then nil
|
|
118
|
-
else raise CliError, 'unexpected value type for workspace'
|
|
119
|
-
end
|
|
120
|
-
@cache_workspace_info =
|
|
121
|
-
begin
|
|
122
|
-
aoc_api.read("workspaces/#{ws_id}")[:data]
|
|
123
|
-
rescue Aspera::RestCallError => e
|
|
124
|
-
Log.log.debug(e.message)
|
|
125
|
-
{ 'id' => :undefined, 'name' => :undefined }
|
|
126
|
-
end
|
|
127
|
-
Log.dump(:current_workspace_info, @cache_workspace_info)
|
|
128
|
-
# display workspace
|
|
129
|
-
default_flag = @cache_workspace_info['id'] == default_workspace_id ? ' (default)' : ''
|
|
130
|
-
formatter.display_status("Current Workspace: #{@cache_workspace_info['name'].to_s.red}#{default_flag}")
|
|
131
|
-
return @cache_workspace_info
|
|
205
|
+
raise
|
|
132
206
|
end
|
|
133
207
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return @
|
|
137
|
-
if !aoc_api.url_token_data.nil?
|
|
138
|
-
assert_public_link_types(['view_shared_file'])
|
|
139
|
-
home_node_id = aoc_api.url_token_data['data']['node_id']
|
|
140
|
-
home_file_id = aoc_api.url_token_data['data']['file_id']
|
|
141
|
-
end
|
|
142
|
-
home_node_id ||= current_workspace_info['home_node_id'] || current_workspace_info['node_id']
|
|
143
|
-
home_file_id ||= current_workspace_info['home_file_id']
|
|
144
|
-
if home_node_id.to_s.empty?
|
|
145
|
-
# not part of any workspace, but has some folder shared
|
|
146
|
-
user_info = aoc_api.current_user_info(exception: true)
|
|
147
|
-
home_node_id = user_info['read_only_home_node_id']
|
|
148
|
-
home_file_id = user_info['read_only_home_file_id']
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
raise "Cannot get user's home node id, check your default workspace or specify one" if home_node_id.to_s.empty?
|
|
152
|
-
@cache_home_node_file = {
|
|
153
|
-
node_id: home_node_id,
|
|
154
|
-
file_id: home_file_id
|
|
155
|
-
}
|
|
156
|
-
return @cache_home_node_file
|
|
208
|
+
def aoc_api
|
|
209
|
+
@cache_api_aoc = api_from_options(AoC::API_V1) if @cache_api_aoc.nil?
|
|
210
|
+
return @cache_api_aoc
|
|
157
211
|
end
|
|
158
212
|
|
|
159
213
|
# get identifier or name from command line
|
|
160
214
|
# @return identifier
|
|
161
215
|
def get_resource_id_from_args(resource_class_path)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
# try to find item by name (single partial match or exact match)
|
|
166
|
-
l_res_id = aoc_api.lookup_by_name(resource_class_path, l_res_name)['id'] unless l_res_name.nil?
|
|
167
|
-
# if no name or id option, taken on command line (after command)
|
|
168
|
-
if l_res_id.nil?
|
|
169
|
-
l_res_id = options.get_next_argument('identifier')
|
|
170
|
-
l_res_id = aoc_api.lookup_by_name(resource_class_path, options.get_next_argument('identifier'))['id'] if l_res_id.eql?(ENTITY_NAME_SPECIFIER)
|
|
216
|
+
return instance_identifier do |field, value|
|
|
217
|
+
assert(field.eql?('name'), exception_class: Cli::BadArgument){'only selection by name is supported'}
|
|
218
|
+
aoc_api.lookup_by_name(resource_class_path, value)['id']
|
|
171
219
|
end
|
|
172
|
-
return l_res_id
|
|
173
220
|
end
|
|
174
221
|
|
|
175
222
|
def get_resource_path_from_args(resource_class_path)
|
|
176
223
|
return "#{resource_class_path}/#{get_resource_id_from_args(resource_class_path)}"
|
|
177
224
|
end
|
|
178
225
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
# Call aoc_api.read with same parameters.
|
|
185
|
-
# Use paging if necessary to get all results
|
|
186
|
-
# @return [Hash] {list: , total: }
|
|
187
|
-
def read_with_paging(resource_class_path, base_query)
|
|
188
|
-
raise 'Query must be Hash' unless base_query.is_a?(Hash)
|
|
226
|
+
# Call block with same query using paging and response information
|
|
227
|
+
# @return [Hash] {data: , total: }
|
|
228
|
+
def api_call_paging(base_query={})
|
|
229
|
+
assert_type(base_query, Hash){'query'}
|
|
230
|
+
assert(block_given?)
|
|
189
231
|
# set default large page if user does not specify own parameters. AoC Caps to 1000 anyway
|
|
190
232
|
base_query['per_page'] = 1000 unless base_query.key?('per_page')
|
|
191
|
-
max_items = base_query
|
|
192
|
-
base_query.delete(
|
|
193
|
-
max_pages = base_query[MAX_PAGES]
|
|
194
|
-
base_query.delete(MAX_PAGES)
|
|
233
|
+
max_items = base_query.delete(MAX_ITEMS)
|
|
234
|
+
max_pages = base_query.delete(MAX_PAGES)
|
|
195
235
|
item_list = []
|
|
196
236
|
total_count = nil
|
|
197
237
|
current_page = base_query['page']
|
|
@@ -200,7 +240,7 @@ module Aspera
|
|
|
200
240
|
loop do
|
|
201
241
|
query = base_query.clone
|
|
202
242
|
query['page'] = current_page
|
|
203
|
-
result =
|
|
243
|
+
result = yield(query)
|
|
204
244
|
total_count = result[:http]['X-Total-Count']
|
|
205
245
|
page_count += 1
|
|
206
246
|
current_page += 1
|
|
@@ -208,10 +248,40 @@ module Aspera
|
|
|
208
248
|
break if add_items.empty?
|
|
209
249
|
# append new items to full list
|
|
210
250
|
item_list += add_items
|
|
211
|
-
break if !
|
|
212
|
-
break if !
|
|
251
|
+
break if !max_items.nil? && item_list.count >= max_items
|
|
252
|
+
break if !max_pages.nil? && page_count >= max_pages
|
|
213
253
|
end
|
|
214
|
-
|
|
254
|
+
item_list = item_list[0..max_items - 1] if !max_items.nil? && item_list.count > max_items
|
|
255
|
+
return {data: item_list, total: total_count}
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# read using the query and paging
|
|
259
|
+
# @return [Hash] {data: , total: }
|
|
260
|
+
def api_read_all(resource_class_path, base_query={})
|
|
261
|
+
return api_call_paging(base_query) do |query|
|
|
262
|
+
aoc_api.read(resource_class_path, query)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# list all entities, given additional, default and user's queries
|
|
267
|
+
def result_list(resource_class_path, fields: nil, base_query: {}, default_query: {})
|
|
268
|
+
assert_type(base_query, Hash)
|
|
269
|
+
assert_type(default_query, Hash)
|
|
270
|
+
user_query = query_read_delete(default: default_query)
|
|
271
|
+
# caller may add specific modifications or checks
|
|
272
|
+
yield(user_query) if block_given?
|
|
273
|
+
return {type: :object_list, fields: fields}.merge(api_read_all(resource_class_path, base_query.merge(user_query)))
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def resolve_dropbox_name_default_ws_id(query)
|
|
277
|
+
if query.key?('dropbox_name')
|
|
278
|
+
# convenience: specify name instead of id
|
|
279
|
+
raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
|
|
280
|
+
query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query['dropbox_name'])['id']
|
|
281
|
+
query.delete('dropbox_name')
|
|
282
|
+
end
|
|
283
|
+
query['workspace_id'] ||= aoc_api.context[:workspace_id] unless aoc_api.context[:workspace_id].eql?(:undefined)
|
|
284
|
+
query['exclude_dropbox_packages'] = true unless query.key?('dropbox_id')
|
|
215
285
|
end
|
|
216
286
|
|
|
217
287
|
NODE4_EXT_COMMANDS = %i[transfer].concat(Node::COMMANDS_GEN4).freeze
|
|
@@ -221,33 +291,32 @@ module Aspera
|
|
|
221
291
|
# @param scope [String] node scope, or nil (admin)
|
|
222
292
|
def execute_nodegen4_command(command_repo, node_id, file_id: nil, scope: nil)
|
|
223
293
|
top_node_api = aoc_api.node_api_from(
|
|
224
|
-
node_id:
|
|
225
|
-
workspace_id:
|
|
226
|
-
workspace_name:
|
|
227
|
-
scope:
|
|
294
|
+
node_id: node_id,
|
|
295
|
+
workspace_id: aoc_api.context[:workspace_id],
|
|
296
|
+
workspace_name: aoc_api.context[:workspace_name],
|
|
297
|
+
scope: scope
|
|
228
298
|
)
|
|
229
299
|
file_id = top_node_api.read("access_keys/#{top_node_api.app_info[:node_info]['access_key']}")[:data]['root_file_id'] if file_id.nil?
|
|
230
|
-
node_plugin = Node.new(@agents
|
|
231
|
-
skip_basic_auth_options: true,
|
|
232
|
-
skip_node_options: true,
|
|
233
|
-
node_api: top_node_api))
|
|
300
|
+
node_plugin = Node.new(@agents, api: top_node_api)
|
|
234
301
|
case command_repo
|
|
235
302
|
when *Node::COMMANDS_GEN4
|
|
236
303
|
return node_plugin.execute_command_gen4(command_repo, file_id)
|
|
237
304
|
when :transfer
|
|
238
305
|
# client side is agent
|
|
239
|
-
# server side is
|
|
306
|
+
# server side is transfer server
|
|
240
307
|
# in same workspace
|
|
241
|
-
|
|
242
|
-
|
|
308
|
+
push_pull = options.get_next_argument('direction', expected: %i[push pull])
|
|
309
|
+
source_folder = options.get_next_argument('folder of source files', type: String)
|
|
310
|
+
case push_pull
|
|
243
311
|
when :push
|
|
244
312
|
client_direction = Fasp::TransferSpec::DIRECTION_SEND
|
|
245
|
-
client_folder =
|
|
313
|
+
client_folder = source_folder
|
|
246
314
|
server_folder = transfer.destination_folder(client_direction)
|
|
247
315
|
when :pull
|
|
248
316
|
client_direction = Fasp::TransferSpec::DIRECTION_RECEIVE
|
|
249
317
|
client_folder = transfer.destination_folder(client_direction)
|
|
250
|
-
server_folder =
|
|
318
|
+
server_folder = source_folder
|
|
319
|
+
else error_unreachable_line
|
|
251
320
|
end
|
|
252
321
|
client_apfid = top_node_api.resolve_api_fid(file_id, client_folder)
|
|
253
322
|
server_apfid = top_node_api.resolve_api_fid(file_id, server_folder)
|
|
@@ -268,9 +337,9 @@ module Aspera
|
|
|
268
337
|
server_apfid[:file_id],
|
|
269
338
|
client_direction,
|
|
270
339
|
add_ts)))
|
|
271
|
-
else
|
|
340
|
+
else error_unreachable_line
|
|
272
341
|
end # command_repo
|
|
273
|
-
|
|
342
|
+
error_unreachable_line
|
|
274
343
|
end # execute_nodegen4_command
|
|
275
344
|
|
|
276
345
|
def execute_admin_action
|
|
@@ -282,14 +351,14 @@ module Aspera
|
|
|
282
351
|
command_auth_prov = options.get_next_command(%i[list update])
|
|
283
352
|
case command_auth_prov
|
|
284
353
|
when :list
|
|
285
|
-
|
|
286
|
-
return {type: :object_list, data: providers}
|
|
354
|
+
return result_list('admin/auth_providers')
|
|
287
355
|
when :update
|
|
288
356
|
raise 'not implemented'
|
|
289
357
|
end
|
|
290
358
|
when :subscription
|
|
291
359
|
org = aoc_api.read('organization')[:data]
|
|
292
|
-
bss_api =
|
|
360
|
+
bss_api = api_from_options('bss/platform')
|
|
361
|
+
# cspell:disable
|
|
293
362
|
graphql_query = "
|
|
294
363
|
query ($organization_id: ID!) {
|
|
295
364
|
aoc (organization_id: $organization_id) {
|
|
@@ -338,17 +407,18 @@ module Aspera
|
|
|
338
407
|
}
|
|
339
408
|
}
|
|
340
409
|
"
|
|
410
|
+
# cspell:enable
|
|
341
411
|
result = bss_api.create('graphql', {'variables' => {'organization_id' => org['id']}, 'query' => graphql_query})[:data]['data']
|
|
342
412
|
return {type: :single_object, data: result['aoc']['bssSubscription']}
|
|
343
413
|
when :ats
|
|
344
414
|
ats_api = Rest.new(aoc_api.params.deep_merge({
|
|
345
|
-
base_url: aoc_api.params[:base_url]
|
|
415
|
+
base_url: "#{aoc_api.params[:base_url]}/admin/ats/pub/v1",
|
|
346
416
|
auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
|
|
347
417
|
}))
|
|
348
|
-
return Ats.new(@agents
|
|
418
|
+
return Ats.new(@agents).execute_action_gen(ats_api)
|
|
349
419
|
when :analytics
|
|
350
420
|
analytics_api = Rest.new(aoc_api.params.deep_merge({
|
|
351
|
-
base_url: aoc_api.params[:base_url].gsub('/api/v1', '')
|
|
421
|
+
base_url: "#{aoc_api.params[:base_url].gsub('/api/v1', '')}/analytics/v2",
|
|
352
422
|
auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
|
|
353
423
|
}))
|
|
354
424
|
command_analytics = options.get_next_command(%i[application_events transfers])
|
|
@@ -359,25 +429,28 @@ module Aspera
|
|
|
359
429
|
return {type: :object_list, data: events}
|
|
360
430
|
when :transfers
|
|
361
431
|
event_type = command_analytics.to_s
|
|
362
|
-
filter_resource = options.
|
|
363
|
-
filter_id = options.
|
|
432
|
+
filter_resource = options.get_next_argument('resource', expected: %i[organizations users nodes])
|
|
433
|
+
filter_id = options.get_next_argument('identifier', mandatory: false) ||
|
|
364
434
|
case filter_resource
|
|
365
|
-
when
|
|
366
|
-
when
|
|
367
|
-
when
|
|
368
|
-
else
|
|
435
|
+
when :organizations then aoc_api.current_user_info['organization_id']
|
|
436
|
+
when :users then aoc_api.current_user_info['id']
|
|
437
|
+
when :nodes then aoc_api.current_user_info['id'] # TODO: consistent ? # rubocop:disable Lint/DuplicateBranch
|
|
438
|
+
else error_unreachable_line
|
|
369
439
|
end
|
|
370
440
|
filter = options.get_option(:query) || {}
|
|
371
|
-
raise 'query must be Hash' unless filter.is_a?(Hash)
|
|
372
441
|
filter['limit'] ||= 100
|
|
373
442
|
if options.get_option(:once_only, mandatory: true)
|
|
374
443
|
saved_date = []
|
|
375
444
|
start_date_persistency = PersistencyActionOnce.new(
|
|
376
445
|
manager: @agents[:persistency],
|
|
377
446
|
data: saved_date,
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
447
|
+
id: IdGenerator.from_list([
|
|
448
|
+
'aoc_ana_date',
|
|
449
|
+
options.get_option(:url, mandatory: true),
|
|
450
|
+
aoc_api.context(:files)[:workspace_name],
|
|
451
|
+
filter_resource.to_s,
|
|
452
|
+
filter_id
|
|
453
|
+
]))
|
|
381
454
|
start_date_time = saved_date.first
|
|
382
455
|
stop_date_time = Time.now.utc.strftime('%FT%T.%LZ')
|
|
383
456
|
# Log.log().error("start: #{start_date_time}")
|
|
@@ -388,7 +461,7 @@ module Aspera
|
|
|
388
461
|
end
|
|
389
462
|
events = analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}", query_read_delete(default: filter))[:data][event_type]
|
|
390
463
|
start_date_persistency&.save
|
|
391
|
-
if !options.get_option(:
|
|
464
|
+
if !options.get_option(:notify_to).nil?
|
|
392
465
|
events.each do |tr_event|
|
|
393
466
|
config.send_email_template(values: {ev: tr_event})
|
|
394
467
|
end
|
|
@@ -404,7 +477,7 @@ module Aspera
|
|
|
404
477
|
when :self, :organization then resource_type
|
|
405
478
|
when :client_registration_token, :client_access_key then "admin/#{resource_type}s"
|
|
406
479
|
when :application then 'admin/apps_new'
|
|
407
|
-
when :dropbox then resource_type
|
|
480
|
+
when :dropbox then "#{resource_type}es"
|
|
408
481
|
when :kms_profile then "integrations/#{resource_type}s"
|
|
409
482
|
else "#{resource_type}s"
|
|
410
483
|
end
|
|
@@ -428,9 +501,7 @@ module Aspera
|
|
|
428
501
|
id_result = 'token' if resource_class_path.eql?('admin/client_registration_tokens')
|
|
429
502
|
# TODO: report inconsistency: creation url is !=, and does not return id.
|
|
430
503
|
resource_class_path = 'admin/client_registration/token' if resource_class_path.eql?('admin/client_registration_tokens')
|
|
431
|
-
|
|
432
|
-
return do_bulk_operation(list_or_one, 'created', id_result: id_result) do |params|
|
|
433
|
-
raise 'expecting Hash' unless params.is_a?(Hash)
|
|
504
|
+
return do_bulk_operation(command: command, descr: 'creation data', id_result: id_result) do |params|
|
|
434
505
|
aoc_api.create(resource_class_path, params)[:data]
|
|
435
506
|
end
|
|
436
507
|
when :list
|
|
@@ -450,35 +521,38 @@ module Aspera
|
|
|
450
521
|
when :group_membership then default_fields.push(*%w[group_id member_type member_id])
|
|
451
522
|
when :workspace_membership then default_fields.push(*%w[workspace_id member_type member_id])
|
|
452
523
|
end
|
|
453
|
-
|
|
454
|
-
formatter.display_item_count(items[:list].length, items[:total])
|
|
455
|
-
return {type: :object_list, data: items[:list], fields: default_fields}
|
|
524
|
+
return result_list(resource_class_path, fields: default_fields, default_query: default_query)
|
|
456
525
|
when :show
|
|
457
526
|
object = aoc_api.read(resource_instance_path)[:data]
|
|
527
|
+
# default: show all, but certificate
|
|
458
528
|
fields = object.keys.reject{|k|k.eql?('certificate')}
|
|
459
529
|
return { type: :single_object, data: object, fields: fields }
|
|
460
530
|
when :modify
|
|
461
|
-
changes = options.get_next_argument('
|
|
462
|
-
|
|
463
|
-
|
|
531
|
+
changes = options.get_next_argument('properties', type: Hash)
|
|
532
|
+
return do_bulk_operation(command: command, descr: 'identifier', values: res_id) do |one_id|
|
|
533
|
+
aoc_api.update("#{resource_class_path}/#{one_id}", changes)
|
|
534
|
+
{'id' => one_id}
|
|
535
|
+
end
|
|
464
536
|
when :delete
|
|
465
|
-
return do_bulk_operation(
|
|
537
|
+
return do_bulk_operation(command: command, descr: 'identifier', values: res_id) do |one_id|
|
|
466
538
|
aoc_api.delete("#{resource_class_path}/#{one_id}")
|
|
467
539
|
{'id' => one_id}
|
|
468
540
|
end
|
|
469
541
|
when :set_pub_key
|
|
470
542
|
# special : reads private and generate public
|
|
471
|
-
the_private_key = options.get_next_argument('private_key')
|
|
543
|
+
the_private_key = options.get_next_argument('private_key PEM value', type: String)
|
|
472
544
|
the_public_key = OpenSSL::PKey::RSA.new(the_private_key).public_key.to_s
|
|
473
545
|
aoc_api.update(resource_instance_path, {jwt_grant_enabled: true, public_key: the_public_key})
|
|
474
546
|
return Main.result_success
|
|
475
547
|
when :do
|
|
476
548
|
command_repo = options.get_next_command(NODE4_EXT_COMMANDS)
|
|
549
|
+
# init context
|
|
550
|
+
aoc_api.context(:files)
|
|
477
551
|
return execute_nodegen4_command(command_repo, res_id)
|
|
478
|
-
else
|
|
552
|
+
else error_unexpected_value(command)
|
|
479
553
|
end
|
|
480
554
|
when :usage_reports
|
|
481
|
-
return
|
|
555
|
+
return result_list('usage_reports', base_query: {workspace_id: aoc_api.context(:files)[:workspace_id]})
|
|
482
556
|
end
|
|
483
557
|
end
|
|
484
558
|
|
|
@@ -487,6 +561,15 @@ module Aspera
|
|
|
487
561
|
|
|
488
562
|
def execute_action
|
|
489
563
|
command = options.get_next_command(ACTIONS)
|
|
564
|
+
if %i[files packages].include?(command)
|
|
565
|
+
default_flag = ' (default)' if options.get_option(:workspace).eql?(:default)
|
|
566
|
+
app_context = aoc_api.context(command)
|
|
567
|
+
formatter.display_status("Workspace: #{app_context[:workspace_name].to_s.red}#{default_flag}")
|
|
568
|
+
if !aoc_api.private_link.nil?
|
|
569
|
+
folder_name = aoc_api.node_api_from(node_id: app_context[:home_node_id]).read("files/#{app_context[:home_file_id]}")[:data]['name']
|
|
570
|
+
formatter.display_status("Private Folder: #{folder_name}")
|
|
571
|
+
end
|
|
572
|
+
end
|
|
490
573
|
case command
|
|
491
574
|
when :reminder
|
|
492
575
|
# send an email reminder with list of orgs
|
|
@@ -502,53 +585,59 @@ module Aspera
|
|
|
502
585
|
when :tier_restrictions
|
|
503
586
|
return { type: :single_object, data: aoc_api.read('tier_restrictions')[:data] }
|
|
504
587
|
when :user
|
|
505
|
-
case options.get_next_command(%i[workspaces profile])
|
|
588
|
+
case options.get_next_command(%i[workspaces profile preferences])
|
|
506
589
|
# when :settings
|
|
507
590
|
# return {type: :object_list,data: aoc_api.read('client_settings/')[:data]}
|
|
508
591
|
when :workspaces
|
|
509
592
|
case options.get_next_command(%i[list current])
|
|
510
593
|
when :list
|
|
511
|
-
return
|
|
594
|
+
return result_list('workspaces', fields: %w[id name])
|
|
512
595
|
when :current
|
|
513
|
-
return { type: :single_object, data:
|
|
596
|
+
return { type: :single_object, data: aoc_api.read("workspaces/#{aoc_api.context(:files)[:workspace_id]}")[:data] }
|
|
514
597
|
end
|
|
515
598
|
when :profile
|
|
516
599
|
case options.get_next_command(%i[show modify])
|
|
517
600
|
when :show
|
|
518
601
|
return { type: :single_object, data: aoc_api.current_user_info(exception: true) }
|
|
519
602
|
when :modify
|
|
520
|
-
aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}", options.get_next_argument('
|
|
603
|
+
aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}", options.get_next_argument('properties', type: Hash))
|
|
604
|
+
return Main.result_status('modified')
|
|
605
|
+
end
|
|
606
|
+
when :preferences
|
|
607
|
+
user_preferences_res = "users/#{aoc_api.current_user_info(exception: true)['id']}/user_interaction_preferences"
|
|
608
|
+
case options.get_next_command(%i[show modify])
|
|
609
|
+
when :show
|
|
610
|
+
return { type: :single_object, data: aoc_api.read(user_preferences_res)[:data] }
|
|
611
|
+
when :modify
|
|
612
|
+
aoc_api.update(user_preferences_res, options.get_next_argument('properties', type: Hash))
|
|
521
613
|
return Main.result_status('modified')
|
|
522
614
|
end
|
|
523
615
|
end
|
|
524
616
|
when :packages
|
|
525
|
-
package_command = options.get_next_command(%i[shared_inboxes send
|
|
617
|
+
package_command = options.get_next_command(%i[shared_inboxes send receive list show delete].concat(Node::NODE4_READ_ACTIONS), aliases: {recv: :receive})
|
|
526
618
|
case package_command
|
|
527
619
|
when :shared_inboxes
|
|
528
620
|
case options.get_next_command(%i[list show])
|
|
529
621
|
when :list
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
query['workspace_id'] = current_workspace_info['id'] unless current_workspace_info['id'].eql?(:undefined)
|
|
534
|
-
end
|
|
535
|
-
return {type: :object_list, data: aoc_api.read('dropbox_memberships', query)[:data], fields: ['dropbox_id', 'dropbox.name']}
|
|
622
|
+
default_query = {'embed[]' => 'dropbox', 'aggregate_permissions_by_dropbox' => true, 'sort' => 'dropbox_name'}
|
|
623
|
+
default_query['workspace_id'] = aoc_api.context[:workspace_id] unless aoc_api.context[:workspace_id].eql?(:undefined)
|
|
624
|
+
return result_list('dropbox_memberships', fields: %w[dropbox_id dropbox.name], default_query: default_query)
|
|
536
625
|
when :show
|
|
537
626
|
return {type: :single_object, data: aoc_api.read(get_resource_path_from_args('dropboxes'), query)[:data]}
|
|
538
627
|
end
|
|
539
628
|
when :send
|
|
540
|
-
package_data = value_create_modify(command: package_command
|
|
629
|
+
package_data = value_create_modify(command: package_command)
|
|
541
630
|
new_user_option = options.get_option(:new_user_option)
|
|
542
631
|
option_validate = options.get_option(:validate_metadata)
|
|
543
632
|
# works for both normal usr auth and link auth
|
|
544
|
-
package_data['workspace_id'] ||=
|
|
633
|
+
package_data['workspace_id'] ||= aoc_api.context[:workspace_id]
|
|
545
634
|
|
|
546
|
-
if !aoc_api.
|
|
547
|
-
assert_public_link_types(%w[send_package_to_user send_package_to_dropbox])
|
|
548
|
-
box_type = aoc_api.
|
|
549
|
-
package_data['recipients'] = [{'id' => aoc_api.
|
|
635
|
+
if !aoc_api.public_link.nil?
|
|
636
|
+
aoc_api.assert_public_link_types(%w[send_package_to_user send_package_to_dropbox])
|
|
637
|
+
box_type = aoc_api.public_link['purpose'].split('_').last
|
|
638
|
+
package_data['recipients'] = [{'id' => aoc_api.public_link['data']["#{box_type}_id"], 'type' => box_type}]
|
|
550
639
|
# enforce workspace id from link (should be already ok, but in case user wanted to override)
|
|
551
|
-
package_data['workspace_id'] = aoc_api.
|
|
640
|
+
package_data['workspace_id'] = aoc_api.public_link['data']['workspace_id']
|
|
552
641
|
end
|
|
553
642
|
|
|
554
643
|
# transfer may raise an error
|
|
@@ -556,41 +645,47 @@ module Aspera
|
|
|
556
645
|
Main.result_transfer(transfer.start(created_package[:spec], rest_token: created_package[:node]))
|
|
557
646
|
# return all info on package (especially package id)
|
|
558
647
|
return { type: :single_object, data: created_package[:info]}
|
|
559
|
-
when :
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
648
|
+
when :receive
|
|
649
|
+
ids_to_download = nil
|
|
650
|
+
if !aoc_api.public_link.nil?
|
|
651
|
+
aoc_api.assert_public_link_types(['view_received_package'])
|
|
652
|
+
# set the package id, it will
|
|
653
|
+
ids_to_download = aoc_api.public_link['data']['package_id']
|
|
563
654
|
end
|
|
564
|
-
#
|
|
565
|
-
ids_to_download
|
|
655
|
+
# get from command line unless it was a public link
|
|
656
|
+
ids_to_download ||= instance_identifier
|
|
566
657
|
skip_ids_data = []
|
|
567
658
|
skip_ids_persistency = nil
|
|
568
659
|
if options.get_option(:once_only, mandatory: true)
|
|
660
|
+
# TODO: add query info to id
|
|
569
661
|
skip_ids_persistency = PersistencyActionOnce.new(
|
|
570
662
|
manager: @agents[:persistency],
|
|
571
663
|
data: skip_ids_data,
|
|
572
|
-
id: IdGenerator.from_list(
|
|
573
|
-
|
|
664
|
+
id: IdGenerator.from_list(
|
|
665
|
+
['aoc_recv',
|
|
666
|
+
options.get_option(:url, mandatory: true),
|
|
667
|
+
aoc_api.context[:workspace_id]
|
|
668
|
+
].concat(aoc_api.additional_persistence_ids)))
|
|
574
669
|
end
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
|
|
581
|
-
query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query['dropbox_name'])['id']
|
|
582
|
-
query.delete('dropbox_name')
|
|
583
|
-
end
|
|
584
|
-
query['workspace_id'] ||= current_workspace_info['id'] unless current_workspace_info['id'].eql?(:undefined)
|
|
585
|
-
# get list of packages in inbox
|
|
586
|
-
package_info = aoc_api.read('packages', query)[:data]
|
|
670
|
+
case ids_to_download
|
|
671
|
+
when ExtendedValue::ALL, ExtendedValue::INIT
|
|
672
|
+
query = query_read_delete(default: PACKAGE_RECEIVED_BASE_QUERY)
|
|
673
|
+
assert_type(query, Hash){'query'}
|
|
674
|
+
resolve_dropbox_name_default_ws_id(query)
|
|
587
675
|
# remove from list the ones already downloaded
|
|
588
|
-
|
|
676
|
+
all_ids = api_read_all('packages', query)[:data].map{|e|e['id']}
|
|
677
|
+
if ids_to_download.eql?(ExtendedValue::INIT)
|
|
678
|
+
assert(skip_ids_persistency){'Only with option once_only'}
|
|
679
|
+
skip_ids_persistency.data.clear.concat(all_ids)
|
|
680
|
+
skip_ids_persistency.save
|
|
681
|
+
return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
|
|
682
|
+
end
|
|
589
683
|
# array here
|
|
590
|
-
ids_to_download.reject
|
|
591
|
-
|
|
684
|
+
ids_to_download = all_ids.reject{|id|skip_ids_data.include?(id)}
|
|
685
|
+
else
|
|
686
|
+
ids_to_download = [ids_to_download] unless ids_to_download.is_a?(Array)
|
|
687
|
+
end # ExtendedValue::ALL
|
|
592
688
|
# list here
|
|
593
|
-
ids_to_download = [ids_to_download] unless ids_to_download.is_a?(Array)
|
|
594
689
|
result_transfer = []
|
|
595
690
|
formatter.display_status("found #{ids_to_download.length} package(s).")
|
|
596
691
|
ids_to_download.each do |package_id|
|
|
@@ -598,8 +693,8 @@ module Aspera
|
|
|
598
693
|
formatter.display_status("downloading package: #{package_info['name']}")
|
|
599
694
|
package_node_api = aoc_api.node_api_from(
|
|
600
695
|
node_id: package_info['node_id'],
|
|
601
|
-
workspace_id:
|
|
602
|
-
workspace_name:
|
|
696
|
+
workspace_id: aoc_api.context[:workspace_id],
|
|
697
|
+
workspace_name: aoc_api.context[:workspace_name],
|
|
603
698
|
package_info: package_info)
|
|
604
699
|
statuses = transfer.start(
|
|
605
700
|
package_node_api.transfer_spec_gen4(
|
|
@@ -616,61 +711,48 @@ module Aspera
|
|
|
616
711
|
end
|
|
617
712
|
return Main.result_transfer_multiple(result_transfer)
|
|
618
713
|
when :show
|
|
619
|
-
package_id =
|
|
714
|
+
package_id = instance_identifier
|
|
620
715
|
package_info = aoc_api.read("packages/#{package_id}")[:data]
|
|
621
716
|
return { type: :single_object, data: package_info }
|
|
622
717
|
when :list
|
|
623
718
|
display_fields = %w[id name bytes_transferred]
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
|
|
629
|
-
query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query['dropbox_name'])['id']
|
|
630
|
-
query.delete('dropbox_name')
|
|
631
|
-
end
|
|
632
|
-
if current_workspace_info['id'].eql?(:undefined)
|
|
633
|
-
display_fields.push('workspace_id')
|
|
634
|
-
else
|
|
635
|
-
query['workspace_id'] ||= current_workspace_info['id']
|
|
636
|
-
end
|
|
637
|
-
packages = aoc_api.read('packages', query)[:data]
|
|
638
|
-
return {type: :object_list, data: packages, fields: display_fields}
|
|
719
|
+
display_fields.push('workspace_id') if aoc_api.context[:workspace_id].eql?(:undefined)
|
|
720
|
+
return result_list('packages', fields: display_fields, base_query: PACKAGE_RECEIVED_BASE_QUERY) do |query|
|
|
721
|
+
resolve_dropbox_name_default_ws_id(query)
|
|
722
|
+
end
|
|
639
723
|
when :delete
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
raise 'expecting String identifier' unless id.is_a?(String) || id.is_a?(Integer)
|
|
724
|
+
return do_bulk_operation(command: package_command, descr: 'identifier', values: identifier) do |id|
|
|
725
|
+
assert_values(id.class, [String, Integer]){'identifier'}
|
|
643
726
|
aoc_api.delete("packages/#{id}")[:data]
|
|
644
727
|
end
|
|
645
728
|
when *Node::NODE4_READ_ACTIONS
|
|
646
|
-
package_id =
|
|
729
|
+
package_id = instance_identifier
|
|
647
730
|
package_info = aoc_api.read("packages/#{package_id}")[:data]
|
|
648
|
-
return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['file_id'], scope:
|
|
731
|
+
return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['file_id'], scope: Aspera::Node::SCOPE_USER)
|
|
649
732
|
end
|
|
650
733
|
when :files
|
|
651
734
|
command_repo = options.get_next_command([:short_link].concat(NODE4_EXT_COMMANDS))
|
|
652
735
|
case command_repo
|
|
653
736
|
when *NODE4_EXT_COMMANDS
|
|
654
|
-
return execute_nodegen4_command(command_repo,
|
|
737
|
+
return execute_nodegen4_command(command_repo, aoc_api.context[:home_node_id], file_id: aoc_api.context[:home_file_id], scope: Aspera::Node::SCOPE_USER)
|
|
655
738
|
when :short_link
|
|
656
|
-
# execute action on AoC API
|
|
657
|
-
short_link_command = options.get_next_command(%i[create delete list])
|
|
658
|
-
folder_dest = options.get_next_argument('path')
|
|
659
739
|
link_type = options.get_next_argument('link type', expected: %i[public private])
|
|
740
|
+
short_link_command = options.get_next_command(%i[create delete list])
|
|
741
|
+
folder_dest = options.get_next_argument('path', type: String)
|
|
660
742
|
home_node_api = aoc_api.node_api_from(
|
|
661
|
-
node_id:
|
|
662
|
-
workspace_id:
|
|
663
|
-
workspace_name:
|
|
664
|
-
shared_apfid = home_node_api.resolve_api_fid(
|
|
743
|
+
node_id: aoc_api.context[:home_node_id],
|
|
744
|
+
workspace_id: aoc_api.context[:workspace_id],
|
|
745
|
+
workspace_name: aoc_api.context[:workspace_name])
|
|
746
|
+
shared_apfid = home_node_api.resolve_api_fid(aoc_api.context[:home_file_id], folder_dest)
|
|
665
747
|
folder_info = {
|
|
666
748
|
node_id: shared_apfid[:api].app_info[:node_info]['id'],
|
|
667
749
|
file_id: shared_apfid[:file_id],
|
|
668
|
-
workspace_id:
|
|
750
|
+
workspace_id: aoc_api.context[:workspace_id]
|
|
669
751
|
}
|
|
670
752
|
purpose = case link_type
|
|
671
753
|
when :public then 'token_auth_redirection'
|
|
672
754
|
when :private then 'shared_folder_auth_link'
|
|
673
|
-
else
|
|
755
|
+
else error_unreachable_line
|
|
674
756
|
end
|
|
675
757
|
case short_link_command
|
|
676
758
|
when :delete
|
|
@@ -699,14 +781,12 @@ module Aspera
|
|
|
699
781
|
end
|
|
700
782
|
list_params = {
|
|
701
783
|
json_query: query.to_json,
|
|
702
|
-
edit_access: true,
|
|
703
784
|
purpose: purpose,
|
|
785
|
+
edit_access: true,
|
|
704
786
|
# embed: 'updated_by_user',
|
|
705
787
|
sort: '-created_at'
|
|
706
788
|
}
|
|
707
|
-
|
|
708
|
-
result.each{|i|i.delete('data')}
|
|
709
|
-
return {type: :object_list, data: result}
|
|
789
|
+
return result_list('short_links', fields: Formatter.all_but('data'), base_query: list_params)
|
|
710
790
|
when :create
|
|
711
791
|
creation_params = {
|
|
712
792
|
purpose: purpose,
|
|
@@ -741,8 +821,8 @@ module Aspera
|
|
|
741
821
|
'access_levels' => access_levels,
|
|
742
822
|
'tags' => {
|
|
743
823
|
'url_token' => true,
|
|
744
|
-
'workspace_id' =>
|
|
745
|
-
'workspace_name' =>
|
|
824
|
+
'workspace_id' => aoc_api.context[:workspace_id],
|
|
825
|
+
'workspace_name' => aoc_api.context[:workspace_name],
|
|
746
826
|
'folder_name' => folder_name,
|
|
747
827
|
'created_by_name' => aoc_api.current_user_info['name'],
|
|
748
828
|
'created_by_email' => aoc_api.current_user_info['email'],
|
|
@@ -772,7 +852,7 @@ module Aspera
|
|
|
772
852
|
wf_command = options.get_next_command(%i[action launch].concat(Plugin::ALL_OPS))
|
|
773
853
|
case wf_command
|
|
774
854
|
when *Plugin::ALL_OPS
|
|
775
|
-
return entity_command(wf_command, automation_api, 'workflows'
|
|
855
|
+
return entity_command(wf_command, automation_api, 'workflows')
|
|
776
856
|
when :launch
|
|
777
857
|
wf_id = instance_identifier
|
|
778
858
|
data = automation_api.create("workflows/#{wf_id}/launch", {})[:data]
|
|
@@ -794,106 +874,22 @@ module Aspera
|
|
|
794
874
|
return execute_admin_action
|
|
795
875
|
when :gateway
|
|
796
876
|
require 'aspera/faspex_gw'
|
|
797
|
-
url = value_create_modify(type: String)
|
|
877
|
+
url = value_create_modify(command: command, type: String)
|
|
798
878
|
uri = URI.parse(url)
|
|
799
879
|
server = WebServerSimple.new(uri)
|
|
800
|
-
server.mount(uri.path, Faspex4GWServlet, aoc_api,
|
|
880
|
+
server.mount(uri.path, Faspex4GWServlet, aoc_api, aoc_api.context(:files)[:workspace_id])
|
|
801
881
|
trap('INT') { server.shutdown }
|
|
802
882
|
formatter.display_status("Faspex 4 gateway listening on #{url}")
|
|
803
883
|
Log.log.info("Listening on #{url}")
|
|
804
884
|
# this is blocking until server exits
|
|
805
885
|
server.start
|
|
806
886
|
return Main.result_status('Gateway terminated')
|
|
807
|
-
else
|
|
808
|
-
raise "internal error: #{command}"
|
|
887
|
+
else error_unreachable_line
|
|
809
888
|
end # action
|
|
810
|
-
|
|
811
|
-
end
|
|
812
|
-
|
|
813
|
-
# @param [Hash] params : plugin_sym, instance_url
|
|
814
|
-
# @return [Hash] :preset_value, :test_args
|
|
815
|
-
def wizard(params)
|
|
816
|
-
if params[:prepare]
|
|
817
|
-
organization = AoC.parse_url(params[:instance_url]).first
|
|
818
|
-
# if not defined by user, generate name
|
|
819
|
-
params[:preset_name] ||= [params[:plugin_sym], organization].join('_')
|
|
820
|
-
params[:need_private_key] = true
|
|
821
|
-
return
|
|
822
|
-
end
|
|
823
|
-
options.set_option(:private_key, '@file:' + params[:private_key_path])
|
|
824
|
-
# make username mandatory for jwt, this triggers interactive input
|
|
825
|
-
options.get_option(:username, mandatory: true)
|
|
826
|
-
auto_set_pub_key = false
|
|
827
|
-
auto_set_jwt = false
|
|
828
|
-
use_browser_authentication = false
|
|
829
|
-
if options.get_option(:use_generic_client)
|
|
830
|
-
formatter.display_status('Using global client_id.')
|
|
831
|
-
formatter.display_status('Please Login to your Aspera on Cloud instance.'.red)
|
|
832
|
-
formatter.display_status('Navigate to your "Account Settings"'.red)
|
|
833
|
-
formatter.display_status('Check or update the value of "Public Key" to be:'.red.blink)
|
|
834
|
-
formatter.display_status(params[:pub_key_pem])
|
|
835
|
-
if !options.get_option(:test_mode)
|
|
836
|
-
formatter.display_status('Once updated or validated, press enter.')
|
|
837
|
-
OpenApplication.instance.uri(params[:instance_url])
|
|
838
|
-
$stdin.gets
|
|
839
|
-
end
|
|
840
|
-
else
|
|
841
|
-
formatter.display_status('Using organization specific client_id.')
|
|
842
|
-
if options.get_option(:client_id).nil? || options.get_option(:client_secret).nil?
|
|
843
|
-
formatter.display_status('Please login to your Aspera on Cloud instance.'.red)
|
|
844
|
-
formatter.display_status('Go to: Apps->Admin->Organization->Integrations')
|
|
845
|
-
formatter.display_status('Create or check if there is an existing integration named:')
|
|
846
|
-
formatter.display_status("- name: #{@info[:name]}")
|
|
847
|
-
formatter.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
|
|
848
|
-
formatter.display_status('- origin: localhost')
|
|
849
|
-
formatter.display_status('Once created or identified,')
|
|
850
|
-
formatter.display_status('Please enter:'.red)
|
|
851
|
-
end
|
|
852
|
-
OpenApplication.instance.uri("#{params[:instance_url]}/#{AOC_PATH_API_CLIENTS}")
|
|
853
|
-
options.get_option(:client_id, mandatory: true)
|
|
854
|
-
options.get_option(:client_secret, mandatory: true)
|
|
855
|
-
use_browser_authentication = true
|
|
856
|
-
end
|
|
857
|
-
if use_browser_authentication
|
|
858
|
-
formatter.display_status('We will use web authentication to bootstrap.')
|
|
859
|
-
auto_set_pub_key = true
|
|
860
|
-
auto_set_jwt = true
|
|
861
|
-
aoc_api.oauth.generic_parameters[:grant_method] = :web
|
|
862
|
-
aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
|
|
863
|
-
aoc_api.oauth.specific_parameters[:redirect_uri] = DEFAULT_REDIRECT
|
|
864
|
-
end
|
|
865
|
-
myself = aoc_api.read('self')[:data]
|
|
866
|
-
if auto_set_pub_key
|
|
867
|
-
raise CliError, 'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? || option_override
|
|
868
|
-
formatter.display_status('Updating profile with new key')
|
|
869
|
-
aoc_api.update("users/#{myself['id']}", {'public_key' => params[:pub_key_pem]})
|
|
870
|
-
end
|
|
871
|
-
if auto_set_jwt
|
|
872
|
-
formatter.display_status('Enabling JWT for client')
|
|
873
|
-
aoc_api.update("clients/#{options.get_option(:client_id)}", {'jwt_grant_enabled' => true, 'explicit_authorization_required' => false})
|
|
874
|
-
end
|
|
875
|
-
formatter.display_status("Creating new config preset: #{params[:preset_name]}")
|
|
876
|
-
preset_result = {
|
|
877
|
-
url: params[:instance_url],
|
|
878
|
-
username: myself['email'],
|
|
879
|
-
auth: :jwt.to_s,
|
|
880
|
-
private_key: '@file:' + params[:private_key_path]
|
|
881
|
-
}.stringify_keys
|
|
882
|
-
# set only if non nil
|
|
883
|
-
%i[client_id client_secret].each do |s|
|
|
884
|
-
o = options.get_option(s)
|
|
885
|
-
preset_result[s.to_s] = o unless o.nil?
|
|
886
|
-
end
|
|
887
|
-
return {
|
|
888
|
-
preset_value: preset_result,
|
|
889
|
-
test_args: "#{params[:plugin_sym]} user profile show"
|
|
890
|
-
}
|
|
889
|
+
error_unreachable_line
|
|
891
890
|
end
|
|
892
891
|
|
|
893
|
-
private :
|
|
894
|
-
:home_info,
|
|
895
|
-
:assert_public_link_types,
|
|
896
|
-
:execute_admin_action
|
|
892
|
+
private :execute_admin_action
|
|
897
893
|
end # AoC
|
|
898
894
|
end # Plugins
|
|
899
895
|
end # Cli
|