aspera-cli 4.14.0 → 4.16.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|