aspera-cli 4.10.0 → 4.12.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 +19 -0
- data/CHANGELOG.md +528 -0
- data/CONTRIBUTING.md +143 -0
- data/README.md +977 -589
- data/bin/ascli +4 -4
- data/bin/asession +12 -12
- data/docs/test_env.conf +29 -19
- data/examples/aoc.rb +6 -6
- data/examples/dascli +18 -16
- data/examples/faspex4.rb +15 -15
- data/examples/node.rb +12 -12
- data/examples/proxy.pac +2 -2
- data/examples/server.rb +12 -12
- data/lib/aspera/aoc.rb +344 -272
- data/lib/aspera/ascmd.rb +56 -54
- data/lib/aspera/ats_api.rb +4 -4
- data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
- data/lib/aspera/cli/extended_value.rb +9 -9
- data/lib/aspera/cli/{formater.rb → formatter.rb} +69 -69
- data/lib/aspera/cli/listener/line_dump.rb +1 -1
- data/lib/aspera/cli/listener/logger.rb +1 -1
- data/lib/aspera/cli/listener/progress.rb +5 -6
- data/lib/aspera/cli/listener/progress_multi.rb +16 -21
- data/lib/aspera/cli/main.rb +72 -73
- data/lib/aspera/cli/manager.rb +112 -112
- data/lib/aspera/cli/plugin.rb +68 -48
- data/lib/aspera/cli/plugins/alee.rb +4 -4
- data/lib/aspera/cli/plugins/aoc.rb +322 -720
- data/lib/aspera/cli/plugins/ats.rb +50 -52
- data/lib/aspera/cli/plugins/bss.rb +10 -10
- data/lib/aspera/cli/plugins/config.rb +514 -410
- data/lib/aspera/cli/plugins/console.rb +12 -12
- data/lib/aspera/cli/plugins/cos.rb +18 -20
- data/lib/aspera/cli/plugins/faspex.rb +134 -136
- data/lib/aspera/cli/plugins/faspex5.rb +235 -70
- data/lib/aspera/cli/plugins/node.rb +378 -309
- data/lib/aspera/cli/plugins/orchestrator.rb +52 -49
- data/lib/aspera/cli/plugins/preview.rb +129 -120
- data/lib/aspera/cli/plugins/server.rb +137 -83
- data/lib/aspera/cli/plugins/shares.rb +77 -52
- data/lib/aspera/cli/plugins/sync.rb +13 -33
- data/lib/aspera/cli/transfer_agent.rb +61 -61
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/colors.rb +3 -3
- data/lib/aspera/command_line_builder.rb +78 -74
- data/lib/aspera/cos_node.rb +31 -29
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +30 -28
- data/lib/aspera/fasp/agent_base.rb +17 -15
- data/lib/aspera/fasp/agent_connect.rb +34 -32
- data/lib/aspera/fasp/agent_direct.rb +70 -73
- data/lib/aspera/fasp/agent_httpgw.rb +79 -74
- data/lib/aspera/fasp/agent_node.rb +26 -26
- data/lib/aspera/fasp/agent_trsdk.rb +20 -20
- data/lib/aspera/fasp/error.rb +3 -2
- data/lib/aspera/fasp/error_info.rb +11 -8
- data/lib/aspera/fasp/installation.rb +80 -80
- data/lib/aspera/fasp/listener.rb +2 -2
- data/lib/aspera/fasp/parameters.rb +103 -92
- data/lib/aspera/fasp/parameters.yaml +313 -214
- data/lib/aspera/fasp/resume_policy.rb +10 -10
- data/lib/aspera/fasp/transfer_spec.rb +22 -2
- data/lib/aspera/fasp/uri.rb +7 -7
- data/lib/aspera/faspex_gw.rb +80 -159
- data/lib/aspera/faspex_postproc.rb +77 -0
- data/lib/aspera/hash_ext.rb +3 -3
- data/lib/aspera/id_generator.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +23 -28
- data/lib/aspera/keychain/macos_security.rb +21 -20
- data/lib/aspera/log.rb +13 -13
- data/lib/aspera/nagios.rb +24 -23
- data/lib/aspera/node.rb +217 -38
- data/lib/aspera/oauth.rb +78 -74
- data/lib/aspera/open_application.rb +19 -11
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +13 -13
- data/lib/aspera/preview/file_types.rb +8 -8
- data/lib/aspera/preview/generator.rb +67 -67
- data/lib/aspera/preview/utils.rb +27 -27
- data/lib/aspera/proxy_auto_config.js +63 -63
- data/lib/aspera/proxy_auto_config.rb +19 -19
- data/lib/aspera/rest.rb +65 -67
- data/lib/aspera/rest_call_error.rb +2 -1
- data/lib/aspera/rest_error_analyzer.rb +22 -21
- data/lib/aspera/rest_errors_aspera.rb +16 -16
- data/lib/aspera/secret_hider.rb +17 -14
- data/lib/aspera/ssh.rb +15 -14
- data/lib/aspera/sync.rb +177 -62
- data/lib/aspera/temp_file_manager.rb +2 -2
- data/lib/aspera/uri_reader.rb +4 -4
- data/lib/aspera/web_auth.rb +13 -64
- data/lib/aspera/web_server_simple.rb +76 -0
- data.tar.gz.sig +0 -0
- metadata +11 -6
- metadata.gz.sig +0 -0
@@ -16,334 +16,95 @@ require 'date'
|
|
16
16
|
module Aspera
|
17
17
|
module Cli
|
18
18
|
module Plugins
|
19
|
-
class Aoc < BasicAuthPlugin
|
19
|
+
class Aoc < Aspera::Cli::BasicAuthPlugin
|
20
20
|
class << self
|
21
21
|
def detect(base_url)
|
22
22
|
api = Rest.new({base_url: base_url})
|
23
23
|
# either in standard domain, or product name in page
|
24
24
|
if URI.parse(base_url).host.end_with?(Aspera::AoC::PROD_DOMAIN) ||
|
25
25
|
api.call({operation: 'GET', redirect_max: 1, headers: {'Accept' => 'text/html'}})[:http].body.include?(Aspera::AoC::PRODUCT_NAME)
|
26
|
-
return {product: :aoc,version: 'SaaS' }
|
26
|
+
return {product: :aoc, version: 'SaaS' }
|
27
27
|
end
|
28
28
|
return nil
|
29
29
|
end
|
30
30
|
end
|
31
31
|
# special value for package id
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
KNOWN_AOC_RES = %i[
|
33
|
+
self
|
34
|
+
organization
|
35
|
+
user
|
36
|
+
group
|
37
|
+
group_membership
|
38
|
+
client
|
39
|
+
contact
|
40
|
+
dropbox
|
41
|
+
node
|
42
|
+
operation
|
43
|
+
package
|
44
|
+
saml_configuration
|
45
|
+
workspace
|
46
|
+
workspace_membership
|
47
|
+
dropbox_membership
|
48
|
+
short_link
|
49
|
+
application
|
50
|
+
client_registration_token
|
51
|
+
client_access_key
|
37
52
|
kms_profile].freeze
|
53
|
+
ENTITY_NAME_SPECIFIER = 'name'
|
54
|
+
PACKAGE_QUERY_DEFAULT = {'archived' => false, 'exclude_dropbox_packages' => true, 'has_content' => true, 'received' => true}.freeze
|
38
55
|
|
39
56
|
def initialize(env)
|
40
57
|
super(env)
|
41
|
-
@
|
42
|
-
@
|
43
|
-
@
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
options.
|
48
|
-
options.
|
49
|
-
options.add_opt_simple(:
|
50
|
-
options.add_opt_simple(:
|
51
|
-
options.add_opt_simple(:
|
52
|
-
options.add_opt_simple(:
|
53
|
-
options.add_opt_simple(:
|
54
|
-
options.add_opt_simple(:
|
55
|
-
options.add_opt_simple(:
|
56
|
-
options.add_opt_simple(:
|
57
|
-
options.
|
58
|
-
options.
|
59
|
-
options.
|
60
|
-
options.
|
61
|
-
options.
|
62
|
-
options.
|
63
|
-
options.set_option(:
|
64
|
-
options.set_option(:validate_metadata,:yes)
|
65
|
-
options.set_option(:new_user_option,{'package_contact' => true})
|
66
|
-
options.set_option(:operation,:push)
|
67
|
-
options.set_option(:auth,:jwt)
|
68
|
-
options.set_option(:scope,AoC::SCOPE_FILES_USER)
|
69
|
-
options.set_option(:private_key,'@file:' + env[:private_key_path]) if env[:private_key_path].is_a?(String)
|
70
|
-
options.set_option(:workspace,:default)
|
58
|
+
@cache_workspace_info = nil
|
59
|
+
@cache_home_node_file = nil
|
60
|
+
@cache_api_aoc = nil
|
61
|
+
options.add_opt_list(:auth, Oauth::STD_AUTH_TYPES, 'OAuth type of authentication')
|
62
|
+
options.add_opt_list(:operation, %i[push pull], 'client operation for transfers')
|
63
|
+
options.add_opt_simple(:client_id, 'OAuth API client identifier')
|
64
|
+
options.add_opt_simple(:client_secret, 'OAuth API client secret')
|
65
|
+
options.add_opt_simple(:redirect_uri, 'OAuth API client redirect URI')
|
66
|
+
options.add_opt_simple(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
|
67
|
+
options.add_opt_simple(:scope, 'OAuth scope for AoC API calls')
|
68
|
+
options.add_opt_simple(:passphrase, 'RSA private key passphrase')
|
69
|
+
options.add_opt_simple(:workspace, 'Name of workspace')
|
70
|
+
options.add_opt_simple(:name, "Resource name (prefer to use keyword #{ENTITY_NAME_SPECIFIER})")
|
71
|
+
options.add_opt_simple(:link, 'Public link to shared resource')
|
72
|
+
options.add_opt_simple(:new_user_option, 'New user creation option for unknown package recipients')
|
73
|
+
options.add_opt_simple(:from_folder, 'Source folder for Folder-to-Folder transfer')
|
74
|
+
options.add_opt_boolean(:validate_metadata, 'Validate shared inbox metadata')
|
75
|
+
options.set_option(:validate_metadata, :yes)
|
76
|
+
options.set_option(:operation, :push)
|
77
|
+
options.set_option(:auth, :jwt)
|
78
|
+
options.set_option(:scope, AoC::SCOPE_FILES_USER)
|
79
|
+
options.set_option(:private_key, '@file:' + env[:private_key_path]) if env[:private_key_path].is_a?(String)
|
80
|
+
options.set_option(:workspace, :default)
|
71
81
|
options.parse_options!
|
72
|
-
|
73
|
-
|
82
|
+
# add node plugin options
|
83
|
+
Node.new(env.merge({man_only: true, skip_basic_auth_options: true}))
|
84
|
+
end
|
85
|
+
|
86
|
+
# build list of options for AoC API, based on options of CLI
|
87
|
+
def aoc_params(subpath)
|
88
|
+
# copy command line options to args
|
89
|
+
return Aspera::AoC::OPTIONS_NEW.each_with_object({subpath: subpath}){|i, m|m[i] = options.get_option(i)}
|
74
90
|
end
|
75
91
|
|
76
92
|
def aoc_api
|
77
|
-
if @
|
78
|
-
@
|
93
|
+
if @cache_api_aoc.nil?
|
94
|
+
@cache_api_aoc = AoC.new(aoc_params(AoC::API_V1))
|
79
95
|
# add keychain for access key secrets
|
80
|
-
@
|
96
|
+
@cache_api_aoc.secret_finder = @agents[:config]
|
81
97
|
end
|
82
|
-
return @
|
83
|
-
end
|
84
|
-
|
85
|
-
# starts transfer using transfer agent
|
86
|
-
def transfer_start(app,direction,node_file,ts_add)
|
87
|
-
ts_add.deep_merge!(AoC.analytics_ts(app,direction,@workspace_info['id'],@workspace_info['name']))
|
88
|
-
ts_add.deep_merge!(aoc_api.console_ts(app))
|
89
|
-
return transfer.start(*aoc_api.tr_spec(app,direction,node_file,ts_add))
|
90
|
-
end
|
91
|
-
|
92
|
-
NODE4_CMD_PATH = %i[bearer_token_node node_info browse find]
|
93
|
-
NODE4_COMMANDS = [NODE4_CMD_PATH,%i[mkdir rename delete upload download transfer http_node_download v3 file]].flatten.freeze
|
94
|
-
|
95
|
-
def execute_node_gen4_command(command_repo,top_node_file)
|
96
|
-
case command_repo
|
97
|
-
when :bearer_token_node
|
98
|
-
thepath = options.get_next_argument('path')
|
99
|
-
node_file = aoc_api.resolve_node_file(top_node_file,thepath)
|
100
|
-
node_api = aoc_api.get_node_api(node_file[:node_info], use_secret: false)
|
101
|
-
return Main.result_status(node_api.oauth_token)
|
102
|
-
when :node_info
|
103
|
-
thepath = options.get_next_argument('path')
|
104
|
-
node_file = aoc_api.resolve_node_file(top_node_file,thepath)
|
105
|
-
node_api = aoc_api.get_node_api(node_file[:node_info], use_secret: false)
|
106
|
-
return {type: :single_object,data: {
|
107
|
-
url: node_file[:node_info]['url'],
|
108
|
-
username: node_file[:node_info]['access_key'],
|
109
|
-
password: node_api.oauth_token,
|
110
|
-
root_id: node_file[:file_id]
|
111
|
-
}}
|
112
|
-
when :browse
|
113
|
-
thepath = options.get_next_argument('path')
|
114
|
-
node_file = aoc_api.resolve_node_file(top_node_file,thepath)
|
115
|
-
node_api = aoc_api.get_node_api(node_file[:node_info])
|
116
|
-
file_info = node_api.read("files/#{node_file[:file_id]}")[:data]
|
117
|
-
if file_info['type'].eql?('folder')
|
118
|
-
result = node_api.read("files/#{node_file[:file_id]}/files",options.get_option(:value))
|
119
|
-
items = result[:data]
|
120
|
-
self.format.display_status("Items: #{result[:data].length}/#{result[:http]['X-Total-Count']}")
|
121
|
-
else
|
122
|
-
items = [file_info]
|
123
|
-
end
|
124
|
-
return {type: :object_list,data: items,fields: %w[name type recursive_size size modified_time access_level]}
|
125
|
-
when :find
|
126
|
-
thepath = options.get_next_argument('path')
|
127
|
-
node_file = aoc_api.resolve_node_file(top_node_file,thepath)
|
128
|
-
test_block = Aspera::Node.file_matcher(options.get_option(:value))
|
129
|
-
return {type: :object_list,data: aoc_api.find_files(node_file,test_block),fields: ['path']}
|
130
|
-
when :mkdir
|
131
|
-
thepath = options.get_next_argument('path')
|
132
|
-
containing_folder_path = thepath.split(AoC::PATH_SEPARATOR)
|
133
|
-
new_folder = containing_folder_path.pop
|
134
|
-
node_file = aoc_api.resolve_node_file(top_node_file,containing_folder_path.join(AoC::PATH_SEPARATOR))
|
135
|
-
node_api = aoc_api.get_node_api(node_file[:node_info])
|
136
|
-
result = node_api.create("files/#{node_file[:file_id]}/files",{name: new_folder,type: :folder})[:data]
|
137
|
-
return Main.result_status("created: #{result['name']} (id=#{result['id']})")
|
138
|
-
when :rename
|
139
|
-
thepath = options.get_next_argument('source path')
|
140
|
-
newname = options.get_next_argument('new name')
|
141
|
-
node_file = aoc_api.resolve_node_file(top_node_file,thepath)
|
142
|
-
node_api = aoc_api.get_node_api(node_file[:node_info])
|
143
|
-
result = node_api.update("files/#{node_file[:file_id]}",{name: newname})[:data]
|
144
|
-
return Main.result_status("renamed #{thepath} to #{newname}")
|
145
|
-
when :delete
|
146
|
-
thepath = options.get_next_argument('path')
|
147
|
-
return do_bulk_operation(thepath,'deleted',id_result: 'path') do |l_path|
|
148
|
-
raise "expecting String (path), got #{l_path.class.name} (#{l_path})" unless l_path.is_a?(String)
|
149
|
-
node_file = aoc_api.resolve_node_file(top_node_file,l_path)
|
150
|
-
node_api = aoc_api.get_node_api(node_file[:node_info])
|
151
|
-
result = node_api.delete("files/#{node_file[:file_id]}")[:data]
|
152
|
-
{'path' => l_path}
|
153
|
-
end
|
154
|
-
when :transfer
|
155
|
-
# client side is agent
|
156
|
-
# server side is protocol server
|
157
|
-
# in same workspace
|
158
|
-
server_home_node_file = client_home_node_file = top_node_file
|
159
|
-
# default is push
|
160
|
-
case options.get_option(:operation,is_type: :mandatory)
|
161
|
-
when :push
|
162
|
-
client_tr_oper = Fasp::TransferSpec::DIRECTION_SEND
|
163
|
-
client_folder = options.get_option(:from_folder,is_type: :mandatory)
|
164
|
-
server_folder = transfer.destination_folder(client_tr_oper)
|
165
|
-
when :pull
|
166
|
-
client_tr_oper = Fasp::TransferSpec::DIRECTION_RECEIVE
|
167
|
-
client_folder = transfer.destination_folder(client_tr_oper)
|
168
|
-
server_folder = options.get_option(:from_folder,is_type: :mandatory)
|
169
|
-
end
|
170
|
-
client_node_file = aoc_api.resolve_node_file(client_home_node_file,client_folder)
|
171
|
-
server_node_file = aoc_api.resolve_node_file(server_home_node_file,server_folder)
|
172
|
-
# force node as transfer agent
|
173
|
-
client_node_api = aoc_api.get_node_api(client_node_file[:node_info], use_secret: false)
|
174
|
-
@agents[:transfer].agent_instance = Fasp::AgentNode.new({
|
175
|
-
url: client_node_api.params[:base_url],
|
176
|
-
username: client_node_file[:node_info]['access_key'],
|
177
|
-
password: client_node_api.oauth_token,
|
178
|
-
root_id: client_node_file[:file_id]
|
179
|
-
})
|
180
|
-
# additional node to node TS info
|
181
|
-
add_ts = {
|
182
|
-
'remote_access_key' => server_node_file[:node_info]['access_key'],
|
183
|
-
'destination_root_id' => server_node_file[:file_id],
|
184
|
-
'source_root_id' => client_node_file[:file_id]
|
185
|
-
}
|
186
|
-
return Main.result_transfer(transfer_start(AoC::FILES_APP,client_tr_oper,server_node_file,add_ts))
|
187
|
-
when :upload
|
188
|
-
node_file = aoc_api.resolve_node_file(top_node_file,transfer.destination_folder(Fasp::TransferSpec::DIRECTION_SEND))
|
189
|
-
add_ts = {'tags' => {'aspera' => {'files' => {'parentCwd' => "#{node_file[:node_info]['id']}:#{node_file[:file_id]}"}}}}
|
190
|
-
return Main.result_transfer(transfer_start(AoC::FILES_APP,Fasp::TransferSpec::DIRECTION_SEND,node_file,add_ts))
|
191
|
-
when :download
|
192
|
-
source_paths = transfer.ts_source_paths
|
193
|
-
# special case for AoC : all files must be in same folder
|
194
|
-
source_folder = source_paths.shift['source']
|
195
|
-
# if a single file: split into folder and path
|
196
|
-
if source_paths.empty?
|
197
|
-
source_folder = source_folder.split(AoC::PATH_SEPARATOR)
|
198
|
-
source_paths = [{'source' => source_folder.pop}]
|
199
|
-
source_folder = source_folder.join(AoC::PATH_SEPARATOR)
|
200
|
-
end
|
201
|
-
node_file = aoc_api.resolve_node_file(top_node_file,source_folder)
|
202
|
-
# override paths with just filename
|
203
|
-
add_ts = {'tags' => {'aspera' => {'files' => {'parentCwd' => "#{node_file[:node_info]['id']}:#{node_file[:file_id]}"}}}}
|
204
|
-
add_ts['paths'] = source_paths
|
205
|
-
return Main.result_transfer(transfer_start(AoC::FILES_APP,Fasp::TransferSpec::DIRECTION_RECEIVE,node_file,add_ts))
|
206
|
-
when :http_node_download
|
207
|
-
source_paths = transfer.ts_source_paths
|
208
|
-
source_folder = source_paths.shift['source']
|
209
|
-
if source_paths.empty?
|
210
|
-
source_folder = source_folder.split(AoC::PATH_SEPARATOR)
|
211
|
-
source_paths = [{'source' => source_folder.pop}]
|
212
|
-
source_folder = source_folder.join(AoC::PATH_SEPARATOR)
|
213
|
-
end
|
214
|
-
raise CliBadArgument,'one file at a time only in HTTP mode' if source_paths.length > 1
|
215
|
-
file_name = source_paths.first['source']
|
216
|
-
node_file = aoc_api.resolve_node_file(top_node_file,File.join(source_folder,file_name))
|
217
|
-
node_api = aoc_api.get_node_api(node_file[:node_info])
|
218
|
-
node_api.call(
|
219
|
-
operation: 'GET',
|
220
|
-
subpath: "files/#{node_file[:file_id]}/content",
|
221
|
-
save_to_file: File.join(transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE),file_name))
|
222
|
-
return Main.result_status("downloaded: #{file_name}")
|
223
|
-
when :v3
|
224
|
-
# Note: other common actions are unauthorized with user scope
|
225
|
-
command_legacy = options.get_next_command(Node::SIMPLE_ACTIONS)
|
226
|
-
# TODO: shall we support all methods here ? what if there is a link ?
|
227
|
-
node_api = aoc_api.get_node_api(top_node_file[:node_info])
|
228
|
-
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: node_api)).execute_action(command_legacy)
|
229
|
-
when :file
|
230
|
-
command_node_file = options.get_next_command(%i[show permission modify])
|
231
|
-
file_path = options.get_option(:path)
|
232
|
-
node_file =
|
233
|
-
if !file_path.nil?
|
234
|
-
# directly returns node_file info
|
235
|
-
aoc_api.resolve_node_file(top_node_file,file_path) # TODO: allow follow link ?
|
236
|
-
else
|
237
|
-
# build node_file info from next argument on command line
|
238
|
-
{node_info: top_node_file[:node_info],file_id: instance_identifier}
|
239
|
-
end
|
240
|
-
node_api = aoc_api.get_node_api(node_file[:node_info])
|
241
|
-
case command_node_file
|
242
|
-
when :show
|
243
|
-
items = node_api.read("files/#{node_file[:file_id]}")[:data]
|
244
|
-
return {type: :single_object,data: items}
|
245
|
-
when :modify
|
246
|
-
update_param = options.get_next_argument('update data (Hash)')
|
247
|
-
res = node_api.update("files/#{node_file[:file_id]}",update_param)[:data]
|
248
|
-
return {type: :single_object,data: res}
|
249
|
-
when :permission
|
250
|
-
command_perm = options.get_next_command(%i[list create delete])
|
251
|
-
case command_perm
|
252
|
-
when :list
|
253
|
-
# generic options : TODO: as arg ? option_url_query
|
254
|
-
list_options ||= {'include' => ['[]','access_level','permission_count']}
|
255
|
-
# special value: ALL will show all permissions
|
256
|
-
if !VAL_ALL.eql?(node_file[:file_id])
|
257
|
-
# add which one to get
|
258
|
-
list_options['file_id'] = node_file[:file_id]
|
259
|
-
list_options['inherited'] ||= false
|
260
|
-
end
|
261
|
-
items = node_api.read('permissions',list_options)[:data]
|
262
|
-
return {type: :object_list,data: items}
|
263
|
-
when :delete
|
264
|
-
perm_id=instance_identifier
|
265
|
-
return do_bulk_operation(perm_id,'deleted') do |one_id|
|
266
|
-
node_api.delete("permissions/#{perm_id}")
|
267
|
-
{'id' => one_id}
|
268
|
-
end
|
269
|
-
#node_api.delete("permissions/#{perm_id}")
|
270
|
-
when :create
|
271
|
-
create_param=options.get_next_argument('creation data (Hash)')
|
272
|
-
#access_id = "#{ID_AK_ADMIN}_WS_#{@workspace_info['id']}"
|
273
|
-
default_params = {
|
274
|
-
'file_id' => node_file[:file_id], # mandatory
|
275
|
-
#'access_type' => 'user', # mandatory: user or group
|
276
|
-
#'access_id' => access_id, # id of user or group
|
277
|
-
'access_levels' => Aspera::Node::ACCESS_LEVELS,
|
278
|
-
'tags' => {'aspera' => {'files' => {'workspace' => {
|
279
|
-
'id' => @workspace_info['id'],
|
280
|
-
'workspace_name' => @workspace_info['name'],
|
281
|
-
'user_name' => aoc_api.user_info['name'],
|
282
|
-
'shared_by_user_id' => aoc_api.user_info['id'],
|
283
|
-
'shared_by_name' => aoc_api.user_info['name'],
|
284
|
-
'shared_by_email' => aoc_api.user_info['email'],
|
285
|
-
#'shared_with_name' => access_id,
|
286
|
-
'access_key' => node_file[:node_info]['access_key'],
|
287
|
-
'node' => node_file[:node_info]['name']}}}}}
|
288
|
-
create_param = default_params.deep_merge(create_param)
|
289
|
-
if create_param.has_key?('with')
|
290
|
-
contact_info = aoc_api.lookup_entity_by_name(
|
291
|
-
'contacts',
|
292
|
-
create_param['with'],
|
293
|
-
{'current_workspace_id' => @workspace_info['id'],'context'=> 'share_folder'})
|
294
|
-
create_param.delete('with')
|
295
|
-
create_param['access_type']=contact_info['source_type']
|
296
|
-
create_param['access_id']=contact_info['source_id']
|
297
|
-
create_param['tags']['aspera']['files']['workspace']['shared_with_name']=contact_info['email']
|
298
|
-
end
|
299
|
-
opt_link_name=nil
|
300
|
-
if create_param.has_key?('link_name')
|
301
|
-
opt_link_name=create_param['link_name']
|
302
|
-
create_param.delete('link_name')
|
303
|
-
end
|
304
|
-
# for admin type:
|
305
|
-
#node_file[:node_info]
|
306
|
-
#node_api = aoc_api.get_node_api(node_file[:node_info])
|
307
|
-
created_data = node_api.create('permissions',create_param)[:data]
|
308
|
-
event_creation={
|
309
|
-
'types' => ['permission.created'],
|
310
|
-
'node_id' => node_file[:node_info]['id'],
|
311
|
-
'workspace_id' => @workspace_info['id'],
|
312
|
-
'data' => created_data # Response from previous step
|
313
|
-
}
|
314
|
-
#(optional). The name of the folder to be displayed to the destination user. Use it if its value is different from the "share_as" field.
|
315
|
-
event_creation['link_name']=opt_link_name unless opt_link_name.nil?
|
316
|
-
aoc_api.create('events',event_creation)
|
317
|
-
return { type: :single_object, data: created_data}
|
318
|
-
else raise "internal error:shall not reach here (#{command_perm})"
|
319
|
-
end
|
320
|
-
else raise "internal error:shall not reach here (#{command_node_file})"
|
321
|
-
end
|
322
|
-
end # command_repo
|
323
|
-
raise 'internal error:shall not reach here'
|
324
|
-
end # execute_node_gen4_command
|
325
|
-
AOC_PARAMS_COPY=%i[link url auth client_id client_secret scope redirect_uri private_key passphrase username password].freeze
|
326
|
-
# build constructor option list for AoC based on options of CLI
|
327
|
-
def aoc_params(subpath)
|
328
|
-
# copy command line options to args
|
329
|
-
opt = AOC_PARAMS_COPY.each_with_object({}){|i,m|m[i] = options.get_option(i)}
|
330
|
-
opt[:subpath] = subpath
|
331
|
-
return opt
|
98
|
+
return @cache_api_aoc
|
332
99
|
end
|
333
100
|
|
334
|
-
#
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
def set_workspace_info
|
340
|
-
@url_token_data = aoc_api.url_token_data
|
341
|
-
if @url_token_data.nil?
|
342
|
-
default_workspace_id = aoc_api.user_info['default_workspace_id']
|
343
|
-
@persist_ids = [aoc_api.user_info['id']]
|
101
|
+
# @return [Hash] current workspace information,
|
102
|
+
def current_workspace_info
|
103
|
+
return @cache_workspace_info unless @cache_workspace_info.nil?
|
104
|
+
default_workspace_id = if aoc_api.url_token_data.nil?
|
105
|
+
aoc_api.current_user_info['default_workspace_id']
|
344
106
|
else
|
345
|
-
|
346
|
-
@persist_ids = [] # TODO : @url_token_data['id'] ?
|
107
|
+
aoc_api.url_token_data['data']['workspace_id']
|
347
108
|
end
|
348
109
|
|
349
110
|
ws_name = options.get_option(:workspace)
|
@@ -351,42 +112,42 @@ module Aspera
|
|
351
112
|
case ws_name
|
352
113
|
when :default
|
353
114
|
Log.log.debug('Using default workspace'.green)
|
354
|
-
raise CliError,'No default workspace defined for user, please specify workspace' if default_workspace_id.nil?
|
115
|
+
raise CliError, 'No default workspace defined for user, please specify workspace' if default_workspace_id.nil?
|
355
116
|
default_workspace_id
|
356
|
-
when String then aoc_api.lookup_entity_by_name('workspaces',ws_name)['id']
|
117
|
+
when String then aoc_api.lookup_entity_by_name('workspaces', ws_name)['id']
|
357
118
|
when NilClass then nil
|
358
|
-
else raise CliError,'unexpected value type for workspace'
|
119
|
+
else raise CliError, 'unexpected value type for workspace'
|
359
120
|
end
|
360
|
-
@
|
121
|
+
@cache_workspace_info =
|
361
122
|
begin
|
362
123
|
aoc_api.read("workspaces/#{ws_id}")[:data]
|
363
124
|
rescue Aspera::RestCallError => e
|
364
125
|
Log.log.debug(e.message)
|
365
126
|
{ 'id' => :undefined, 'name' => :undefined }
|
366
127
|
end
|
367
|
-
Log.dump(:
|
128
|
+
Log.dump(:current_workspace_info, @cache_workspace_info)
|
368
129
|
# display workspace
|
369
|
-
|
370
|
-
|
130
|
+
default_flag = @cache_workspace_info['id'] == default_workspace_id ? ' (default)' : ''
|
131
|
+
formatter.display_status("Current Workspace: #{@cache_workspace_info['name'].to_s.red}#{default_flag}")
|
132
|
+
return @cache_workspace_info
|
371
133
|
end
|
372
134
|
|
373
|
-
# @
|
374
|
-
def
|
375
|
-
|
135
|
+
# @return [Hash] with :node_id and :file_id
|
136
|
+
def home_info
|
137
|
+
return @cache_home_node_file unless @cache_home_node_file.nil?
|
138
|
+
if !aoc_api.url_token_data.nil?
|
376
139
|
assert_public_link_types(['view_shared_file'])
|
377
|
-
home_node_id =
|
378
|
-
home_file_id =
|
140
|
+
home_node_id = aoc_api.url_token_data['data']['node_id']
|
141
|
+
home_file_id = aoc_api.url_token_data['data']['file_id']
|
379
142
|
end
|
380
|
-
home_node_id ||=
|
381
|
-
home_file_id ||=
|
143
|
+
home_node_id ||= current_workspace_info['home_node_id'] || current_workspace_info['node_id']
|
144
|
+
home_file_id ||= current_workspace_info['home_file_id']
|
382
145
|
raise "Cannot get user's home node id, check your default workspace or specify one" if home_node_id.to_s.empty?
|
383
|
-
@
|
384
|
-
|
385
|
-
file_id:
|
146
|
+
@cache_home_node_file = {
|
147
|
+
node_id: home_node_id,
|
148
|
+
file_id: home_file_id
|
386
149
|
}
|
387
|
-
|
388
|
-
|
389
|
-
return nil
|
150
|
+
return @cache_home_node_file
|
390
151
|
end
|
391
152
|
|
392
153
|
# get identifier or name from command line
|
@@ -396,11 +157,11 @@ module Aspera
|
|
396
157
|
l_res_name = options.get_option(:name)
|
397
158
|
raise 'Provide either option id or name, not both' unless l_res_id.nil? || l_res_name.nil?
|
398
159
|
# try to find item by name (single partial match or exact match)
|
399
|
-
l_res_id = aoc_api.lookup_entity_by_name(resource_class_path,l_res_name)['id'] unless l_res_name.nil?
|
160
|
+
l_res_id = aoc_api.lookup_entity_by_name(resource_class_path, l_res_name)['id'] unless l_res_name.nil?
|
400
161
|
# if no name or id option, taken on command line (after command)
|
401
162
|
if l_res_id.nil?
|
402
163
|
l_res_id = options.get_next_argument('identifier')
|
403
|
-
l_res_id = aoc_api.lookup_entity_by_name(resource_class_path,options.get_next_argument('identifier'))['id'] if l_res_id.eql?(
|
164
|
+
l_res_id = aoc_api.lookup_entity_by_name(resource_class_path, options.get_next_argument('identifier'))['id'] if l_res_id.eql?(ENTITY_NAME_SPECIFIER)
|
404
165
|
end
|
405
166
|
return l_res_id
|
406
167
|
end
|
@@ -409,129 +170,18 @@ module Aspera
|
|
409
170
|
return "#{resource_class_path}/#{get_resource_id_from_args(resource_class_path)}"
|
410
171
|
end
|
411
172
|
|
412
|
-
# Normalize package creation recipient lists as expected by AoC API
|
413
|
-
# AoC expects {type: , id: }, but ascli allows providing either the native values or just a name
|
414
|
-
# in that case, the name is resolved and replaced with {type: , id: }
|
415
|
-
# @param package_data The whole package creation payload
|
416
|
-
# @param recipient_list_field The field in structure, i.e. recipients or bcc_recipients
|
417
|
-
# @return nil package_data is modified
|
418
|
-
def resolve_package_recipients(package_data,recipient_list_field)
|
419
|
-
return unless package_data.has_key?(recipient_list_field)
|
420
|
-
raise CliBadArgument,"#{recipient_list_field} must be an Array" unless package_data[recipient_list_field].is_a?(Array)
|
421
|
-
new_user_option = options.get_option(:new_user_option,is_type: :mandatory)
|
422
|
-
# list with resolved elements
|
423
|
-
resolved_list = []
|
424
|
-
package_data[recipient_list_field].each do |short_recipient_info|
|
425
|
-
case short_recipient_info
|
426
|
-
when Hash # native API information, check keys
|
427
|
-
raise "#{recipient_list_field} element shall have fields: id and type" unless short_recipient_info.keys.sort.eql?(%w[id type])
|
428
|
-
when String # CLI helper: need to resolve provided name to type/id
|
429
|
-
# email: user, else dropbox
|
430
|
-
entity_type = short_recipient_info.include?('@') ? 'contacts' : 'dropboxes'
|
431
|
-
begin
|
432
|
-
full_recipient_info = aoc_api.lookup_entity_by_name(entity_type,short_recipient_info,{'current_workspace_id' => @workspace_info['id']})
|
433
|
-
rescue RuntimeError => e
|
434
|
-
raise e unless e.message.start_with?(Aspera::AoC::ENTITY_NOT_FOUND)
|
435
|
-
# dropboxes cannot be created on the fly
|
436
|
-
raise "no such shared inbox in workspace #{@workspace_info['name']}" if entity_type.eql?('dropboxes')
|
437
|
-
# unknown user: create it as external user
|
438
|
-
full_recipient_info = aoc_api.create('contacts',{
|
439
|
-
'current_workspace_id' => @workspace_info['id'],
|
440
|
-
'email' => short_recipient_info}.merge(new_user_option))[:data]
|
441
|
-
end
|
442
|
-
short_recipient_info = if entity_type.eql?('dropboxes')
|
443
|
-
{'id' => full_recipient_info['id'],'type' => 'dropbox'}
|
444
|
-
else
|
445
|
-
{'id' => full_recipient_info['source_id'],'type' => full_recipient_info['source_type']}
|
446
|
-
end
|
447
|
-
else # unexpected extended value, must be String or Hash
|
448
|
-
raise "#{recipient_list_field} item must be a String (email, shared inbox) or Hash (id,type)"
|
449
|
-
end # type of recipient info
|
450
|
-
# add original or resolved recipient info
|
451
|
-
resolved_list.push(short_recipient_info)
|
452
|
-
end
|
453
|
-
# replace with resolved elements
|
454
|
-
package_data[recipient_list_field] = resolved_list
|
455
|
-
return nil
|
456
|
-
end
|
457
|
-
|
458
|
-
def normalize_metadata(pkg_data)
|
459
|
-
case pkg_data['metadata']
|
460
|
-
when Array,NilClass # no action
|
461
|
-
when Hash
|
462
|
-
api_meta = []
|
463
|
-
pkg_data['metadata'].each do |k,v|
|
464
|
-
api_meta.push({
|
465
|
-
#'input_type' => 'single-dropdown',
|
466
|
-
'name' => k,
|
467
|
-
'values' => v.is_a?(Array) ? v : [v]
|
468
|
-
})
|
469
|
-
end
|
470
|
-
pkg_data['metadata'] = api_meta
|
471
|
-
else raise "metadata field if not of expected type: #{pkg_meta.class}"
|
472
|
-
end
|
473
|
-
return nil
|
474
|
-
end
|
475
|
-
|
476
|
-
# Check metadata: remove when validation is done server side
|
477
|
-
def validate_metadata(pkg_data)
|
478
|
-
# validate only for shared inboxes
|
479
|
-
return unless
|
480
|
-
pkg_data['recipients'].is_a?(Array) &&
|
481
|
-
pkg_data['recipients'].first.is_a?(Hash) &&
|
482
|
-
pkg_data['recipients'].first.has_key?('type') &&
|
483
|
-
pkg_data['recipients'].first['type'].eql?('dropbox')
|
484
|
-
|
485
|
-
shbx_kid = pkg_data['recipients'].first['id']
|
486
|
-
meta_schema = aoc_api.read("dropboxes/#{shbx_kid}")[:data]['metadata_schema']
|
487
|
-
if meta_schema.nil? || meta_schema.empty?
|
488
|
-
Log.log.debug('no metadata in shared inbox')
|
489
|
-
return
|
490
|
-
end
|
491
|
-
pkg_meta = pkg_data['metadata']
|
492
|
-
raise "package requires metadata: #{meta_schema}" unless pkg_data.has_key?('metadata')
|
493
|
-
raise 'metadata must be an Array' unless pkg_meta.is_a?(Array)
|
494
|
-
Log.dump(:metadata,pkg_meta)
|
495
|
-
pkg_meta.each do |field|
|
496
|
-
raise 'metadata field must be Hash' unless field.is_a?(Hash)
|
497
|
-
raise 'metadata field must have name' unless field.has_key?('name')
|
498
|
-
raise 'metadata field must have values' unless field.has_key?('values')
|
499
|
-
raise 'metadata values must be an Array' unless field['values'].is_a?(Array)
|
500
|
-
raise "unknown metadata field: #{field['name']}" if meta_schema.select{|i|i['name'].eql?(field['name'])}.empty?
|
501
|
-
end
|
502
|
-
meta_schema.each do |field|
|
503
|
-
provided=pkg_meta.select{|i|i['name'].eql?(field['name'])}
|
504
|
-
raise "only one field with name #{field['name']} allowed" if provided.count > 1
|
505
|
-
raise "missing mandatory field: #{field['name']}" if field['required'] && provided.empty?
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
# private
|
510
|
-
def option_url_query(default)
|
511
|
-
query = options.get_option(:query)
|
512
|
-
query = default if query.nil?
|
513
|
-
Log.log.debug("Query=#{query}".bg_red)
|
514
|
-
begin
|
515
|
-
# check it is suitable
|
516
|
-
URI.encode_www_form(query) unless query.nil?
|
517
|
-
rescue StandardError => e
|
518
|
-
raise CliBadArgument,"query must be an extended value which can be encoded with URI.encode_www_form. Refer to manual. (#{e.message})"
|
519
|
-
end
|
520
|
-
return query
|
521
|
-
end
|
522
|
-
|
523
173
|
def assert_public_link_types(expected)
|
524
|
-
raise CliBadArgument,"public link type is #{
|
525
|
-
unless expected.include?(
|
174
|
+
raise CliBadArgument, "public link type is #{aoc_api.url_token_data['purpose']} but action requires one of #{expected.join(',')}" \
|
175
|
+
unless expected.include?(aoc_api.url_token_data['purpose'])
|
526
176
|
end
|
527
177
|
|
528
178
|
# Call aoc_api.read with same parameters.
|
529
179
|
# Use paging if necessary to get all results
|
530
|
-
# @return {list: , total: }
|
531
|
-
def read_with_paging(resource_class_path,base_query)
|
180
|
+
# @return [Hash] {list: , total: }
|
181
|
+
def read_with_paging(resource_class_path, base_query)
|
532
182
|
raise 'Query must be Hash' unless base_query.is_a?(Hash)
|
533
183
|
# set default large page if user does not specify own parameters. AoC Caps to 1000 anyway
|
534
|
-
base_query['per_page'] = 1000 unless base_query.
|
184
|
+
base_query['per_page'] = 1000 unless base_query.key?('per_page')
|
535
185
|
max_items = base_query[MAX_ITEMS]
|
536
186
|
base_query.delete(MAX_ITEMS)
|
537
187
|
max_pages = base_query[MAX_PAGES]
|
@@ -544,7 +194,7 @@ module Aspera
|
|
544
194
|
loop do
|
545
195
|
query = base_query.clone
|
546
196
|
query['page'] = current_page
|
547
|
-
result = aoc_api.read(resource_class_path,query)
|
197
|
+
result = aoc_api.read(resource_class_path, query)
|
548
198
|
total_count = result[:http]['X-Total-Count']
|
549
199
|
page_count += 1
|
550
200
|
current_page += 1
|
@@ -555,12 +205,66 @@ module Aspera
|
|
555
205
|
break if !max_pages.nil? && page_count > max_pages
|
556
206
|
break if !max_items.nil? && item_list.count > max_items
|
557
207
|
end
|
558
|
-
return {list: item_list,total: total_count}
|
208
|
+
return {list: item_list, total: total_count}
|
559
209
|
end
|
560
210
|
|
211
|
+
NODE4_EXT_COMMANDS = %i[transfer].concat(Node::COMMANDS_GEN4).freeze
|
212
|
+
private_constant :NODE4_EXT_COMMANDS
|
213
|
+
|
214
|
+
# @param file_id [String] root file id for the operation (can be AK root, or other, e.g. package, or link)
|
215
|
+
# @param scope [String] node scope, or nil (admin)
|
216
|
+
def execute_nodegen4_command(command_repo, node_id, file_id: nil, scope: nil)
|
217
|
+
top_node_api = aoc_api.node_api_from(node_id: node_id, workspace_info: current_workspace_info, scope: scope)
|
218
|
+
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?
|
219
|
+
node_plugin = Node.new(@agents.merge(
|
220
|
+
skip_basic_auth_options: true,
|
221
|
+
skip_node_options: true,
|
222
|
+
node_api: top_node_api))
|
223
|
+
case command_repo
|
224
|
+
when *Node::COMMANDS_GEN4
|
225
|
+
return node_plugin.execute_command_gen4(command_repo, file_id)
|
226
|
+
when :transfer
|
227
|
+
# client side is agent
|
228
|
+
# server side is protocol server
|
229
|
+
# in same workspace
|
230
|
+
# default is push
|
231
|
+
case options.get_option(:operation, is_type: :mandatory)
|
232
|
+
when :push
|
233
|
+
client_direction = Fasp::TransferSpec::DIRECTION_SEND
|
234
|
+
client_folder = options.get_option(:from_folder, is_type: :mandatory)
|
235
|
+
server_folder = transfer.destination_folder(client_direction)
|
236
|
+
when :pull
|
237
|
+
client_direction = Fasp::TransferSpec::DIRECTION_RECEIVE
|
238
|
+
client_folder = transfer.destination_folder(client_direction)
|
239
|
+
server_folder = options.get_option(:from_folder, is_type: :mandatory)
|
240
|
+
end
|
241
|
+
client_apfid = top_node_api.resolve_api_fid(file_id, client_folder)
|
242
|
+
server_apfid = top_node_api.resolve_api_fid(file_id, server_folder)
|
243
|
+
# force node as transfer agent
|
244
|
+
@agents[:transfer].agent_instance = Fasp::AgentNode.new({
|
245
|
+
url: client_apfid[:api].params[:base_url],
|
246
|
+
username: client_apfid[:api].app_info[:node_info]['access_key'],
|
247
|
+
password: client_apfid[:api].oauth_token,
|
248
|
+
root_id: client_apfid[:file_id]
|
249
|
+
})
|
250
|
+
# additional node to node TS info
|
251
|
+
add_ts = {
|
252
|
+
'remote_access_key' => server_apfid[:api].app_info[:node_info]['access_key'],
|
253
|
+
'destination_root_id' => server_apfid[:file_id],
|
254
|
+
'source_root_id' => client_apfid[:file_id]
|
255
|
+
}
|
256
|
+
return Main.result_transfer(transfer.start(server_apfid[:api].transfer_spec_gen4(
|
257
|
+
server_apfid[:file_id],
|
258
|
+
client_direction,
|
259
|
+
add_ts)))
|
260
|
+
else raise "INTERNAL ERROR: Missing case: #{command_repo}"
|
261
|
+
end # command_repo
|
262
|
+
# raise 'internal error:shall not reach here'
|
263
|
+
end # execute_nodegen4_command
|
264
|
+
|
561
265
|
def execute_admin_action
|
562
266
|
# upgrade scope to admin
|
563
|
-
aoc_api.oauth.
|
267
|
+
aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
|
564
268
|
command_admin = options.get_next_command(%i[ats resource usage_reports analytics subscription auth_providers])
|
565
269
|
case command_admin
|
566
270
|
when :auth_providers
|
@@ -568,7 +272,7 @@ module Aspera
|
|
568
272
|
case command_auth_prov
|
569
273
|
when :list
|
570
274
|
providers = aoc_api.read('admin/auth_providers')[:data]
|
571
|
-
return {type: :object_list,data: providers}
|
275
|
+
return {type: :object_list, data: providers}
|
572
276
|
when :update
|
573
277
|
raise 'not implemented'
|
574
278
|
end
|
@@ -623,69 +327,71 @@ module Aspera
|
|
623
327
|
}
|
624
328
|
}
|
625
329
|
"
|
626
|
-
result = bss_api.create('graphql',{'variables' => {'organization_id' => org['id']},'query' => graphql_query})[:data]['data']
|
627
|
-
return {type: :single_object,data: result['aoc']['bssSubscription']}
|
330
|
+
result = bss_api.create('graphql', {'variables' => {'organization_id' => org['id']}, 'query' => graphql_query})[:data]['data']
|
331
|
+
return {type: :single_object, data: result['aoc']['bssSubscription']}
|
628
332
|
when :ats
|
629
333
|
ats_api = Rest.new(aoc_api.params.deep_merge({
|
630
334
|
base_url: aoc_api.params[:base_url] + '/admin/ats/pub/v1',
|
631
335
|
auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
|
632
336
|
}))
|
633
|
-
return Ats.new(@agents).execute_action_gen(ats_api)
|
337
|
+
return Ats.new(@agents.merge(skip_node_options: true)).execute_action_gen(ats_api)
|
634
338
|
when :analytics
|
635
339
|
analytics_api = Rest.new(aoc_api.params.deep_merge({
|
636
|
-
base_url: aoc_api.params[:base_url].gsub('/api/v1','') + '/analytics/v2',
|
340
|
+
base_url: aoc_api.params[:base_url].gsub('/api/v1', '') + '/analytics/v2',
|
637
341
|
auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
|
638
342
|
}))
|
639
343
|
command_analytics = options.get_next_command(%i[application_events transfers])
|
640
344
|
case command_analytics
|
641
345
|
when :application_events
|
642
346
|
event_type = command_analytics.to_s
|
643
|
-
events = analytics_api.read("organizations/#{aoc_api.
|
644
|
-
return {type: :object_list,data: events}
|
347
|
+
events = analytics_api.read("organizations/#{aoc_api.current_user_info['organization_id']}/#{event_type}")[:data][event_type]
|
348
|
+
return {type: :object_list, data: events}
|
645
349
|
when :transfers
|
646
350
|
event_type = command_analytics.to_s
|
647
351
|
filter_resource = options.get_option(:name) || 'organizations'
|
648
352
|
filter_id = options.get_option(:id) ||
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
353
|
+
case filter_resource
|
354
|
+
when 'organizations' then aoc_api.current_user_info['organization_id']
|
355
|
+
when 'users' then aoc_api.current_user_info['id']
|
356
|
+
when 'nodes' then aoc_api.current_user_info['id'] # TODO: consistent ? # rubocop:disable Lint/DuplicateBranch
|
357
|
+
else raise 'organizations or users for option --name'
|
358
|
+
end
|
655
359
|
filter = options.get_option(:query) || {}
|
656
360
|
raise 'query must be Hash' unless filter.is_a?(Hash)
|
657
361
|
filter['limit'] ||= 100
|
658
|
-
if options.get_option(:once_only,is_type: :mandatory)
|
362
|
+
if options.get_option(:once_only, is_type: :mandatory)
|
659
363
|
saved_date = []
|
660
|
-
|
364
|
+
start_date_persistency = PersistencyActionOnce.new(
|
661
365
|
manager: @agents[:persistency],
|
662
366
|
data: saved_date,
|
663
|
-
ids: IdGenerator.from_list(['aoc_ana_date',options.get_option(:url,is_type: :mandatory)
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
367
|
+
ids: IdGenerator.from_list(['aoc_ana_date', options.get_option(:url, is_type: :mandatory), current_workspace_info['name']].push(
|
368
|
+
filter_resource,
|
369
|
+
filter_id)))
|
370
|
+
start_date_time = saved_date.first
|
371
|
+
stop_date_time = Time.now.utc.strftime('%FT%T.%LZ')
|
372
|
+
# Log.log().error("start: #{start_date_time}")
|
373
|
+
# Log.log().error("end: #{stop_date_time}")
|
374
|
+
saved_date[0] = stop_date_time
|
375
|
+
filter['start_time'] = start_date_time unless start_date_time.nil?
|
376
|
+
filter['stop_time'] = stop_date_time
|
671
377
|
end
|
672
|
-
events = analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}",option_url_query(filter))[:data][event_type]
|
673
|
-
|
378
|
+
events = analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}", option_url_query(filter))[:data][event_type]
|
379
|
+
start_date_persistency&.save
|
674
380
|
if !options.get_option(:notif_to).nil?
|
675
381
|
events.each do |tr_event|
|
676
382
|
config.send_email_template(values: {ev: tr_event})
|
677
383
|
end
|
678
384
|
end
|
679
|
-
return {type: :object_list,data: events}
|
385
|
+
return {type: :object_list, data: events}
|
680
386
|
end
|
681
387
|
when :resource
|
682
|
-
resource_type = options.get_next_argument('resource',expected: KNOWN_AOC_RES)
|
388
|
+
resource_type = options.get_next_argument('resource', expected: KNOWN_AOC_RES)
|
683
389
|
# get path on API, resource type is singular, but api is plural
|
684
390
|
resource_class_path =
|
685
391
|
case resource_type
|
686
392
|
# special cases: singleton, in admin, with x
|
687
|
-
when :self
|
688
|
-
when :client_registration_token
|
393
|
+
when :self, :organization then resource_type
|
394
|
+
when :client_registration_token, :client_access_key then "admin/#{resource_type}s"
|
689
395
|
when :application then 'admin/apps_new'
|
690
396
|
when :dropbox then resource_type.to_s + 'es'
|
691
397
|
when :kms_profile then "integrations/#{resource_type}s"
|
@@ -695,10 +401,9 @@ module Aspera
|
|
695
401
|
singleton_object = %i[self organization].include?(resource_type)
|
696
402
|
global_operations = %i[create list]
|
697
403
|
supported_operations = %i[show modify]
|
698
|
-
supported_operations.push(:delete
|
699
|
-
supported_operations.push(:
|
404
|
+
supported_operations.push(:delete, *global_operations) unless singleton_object
|
405
|
+
supported_operations.push(:do) if resource_type.eql?(:node)
|
700
406
|
supported_operations.push(:set_pub_key) if resource_type.eql?(:client)
|
701
|
-
supported_operations.push(:shared_folder) if resource_type.eql?(:workspace)
|
702
407
|
command = options.get_next_command(supported_operations)
|
703
408
|
# require identifier for non global commands
|
704
409
|
if !singleton_object && !global_operations.include?(command)
|
@@ -712,42 +417,43 @@ module Aspera
|
|
712
417
|
id_result = 'token' if resource_class_path.eql?('admin/client_registration_tokens')
|
713
418
|
# TODO: report inconsistency: creation url is !=, and does not return id.
|
714
419
|
resource_class_path = 'admin/client_registration/token' if resource_class_path.eql?('admin/client_registration_tokens')
|
715
|
-
list_or_one = options.get_next_argument('creation data
|
716
|
-
return do_bulk_operation(list_or_one,'created',id_result: id_result) do |params|
|
420
|
+
list_or_one = options.get_next_argument('creation data', type: Hash)
|
421
|
+
return do_bulk_operation(list_or_one, 'created', id_result: id_result) do |params|
|
717
422
|
raise 'expecting Hash' unless params.is_a?(Hash)
|
718
|
-
aoc_api.create(resource_class_path,params)[:data]
|
423
|
+
aoc_api.create(resource_class_path, params)[:data]
|
719
424
|
end
|
720
425
|
when :list
|
721
426
|
default_fields = ['id']
|
722
427
|
default_query = {}
|
723
428
|
case resource_type
|
724
|
-
when :application
|
725
|
-
|
726
|
-
|
727
|
-
when :
|
429
|
+
when :application
|
430
|
+
default_query = {organization_apps: true}
|
431
|
+
default_fields.push('app_type', 'app_name', 'available', 'direct_authorizations_allowed', 'workspace_authorizations_allowed')
|
432
|
+
when :client, :client_access_key, :dropbox, :group, :package, :saml_configuration, :workspace then default_fields.push('name')
|
433
|
+
when :client_registration_token then default_fields.push('value', 'data.client_subject_scopes', 'created_at')
|
728
434
|
when :contact then default_fields = %w[email name source_id source_type]
|
729
|
-
when :node then default_fields.push('name','host','access_key')
|
435
|
+
when :node then default_fields.push('name', 'host', 'access_key')
|
730
436
|
when :operation then default_fields = nil
|
731
|
-
when :short_link then default_fields.push('short_url','data.url_token_data.purpose')
|
732
|
-
when :user then default_fields.push('name','email')
|
437
|
+
when :short_link then default_fields.push('short_url', 'data.url_token_data.purpose')
|
438
|
+
when :user then default_fields.push('name', 'email')
|
733
439
|
when :group_membership then default_fields.push(*%w[group_id member_type member_id])
|
734
440
|
when :workspace_membership then default_fields.push(*%w[workspace_id member_type member_id])
|
735
441
|
end
|
736
|
-
items = read_with_paging(resource_class_path,option_url_query(default_query))
|
442
|
+
items = read_with_paging(resource_class_path, option_url_query(default_query))
|
737
443
|
count_msg = "Items: #{items[:list].length}/#{items[:total]}"
|
738
444
|
count_msg = count_msg.bg_red unless items[:list].length.eql?(items[:total].to_i)
|
739
|
-
|
740
|
-
return {type: :object_list,data: items[:list],fields: default_fields}
|
445
|
+
formatter.display_status(count_msg)
|
446
|
+
return {type: :object_list, data: items[:list], fields: default_fields}
|
741
447
|
when :show
|
742
448
|
object = aoc_api.read(resource_instance_path)[:data]
|
743
449
|
fields = object.keys.reject{|k|k.eql?('certificate')}
|
744
450
|
return { type: :single_object, data: object, fields: fields }
|
745
451
|
when :modify
|
746
452
|
changes = options.get_next_argument('modified parameters (hash)')
|
747
|
-
aoc_api.update(resource_instance_path,changes)
|
453
|
+
aoc_api.update(resource_instance_path, changes)
|
748
454
|
return Main.result_status('modified')
|
749
455
|
when :delete
|
750
|
-
return do_bulk_operation(res_id,'deleted') do |one_id|
|
456
|
+
return do_bulk_operation(res_id, 'deleted') do |one_id|
|
751
457
|
aoc_api.delete("#{resource_class_path}/#{one_id}")
|
752
458
|
{'id' => one_id}
|
753
459
|
end
|
@@ -755,109 +461,15 @@ module Aspera
|
|
755
461
|
# special : reads private and generate public
|
756
462
|
the_private_key = options.get_next_argument('private_key')
|
757
463
|
the_public_key = OpenSSL::PKey::RSA.new(the_private_key).public_key.to_s
|
758
|
-
aoc_api.update(resource_instance_path,{jwt_grant_enabled: true, public_key: the_public_key})
|
464
|
+
aoc_api.update(resource_instance_path, {jwt_grant_enabled: true, public_key: the_public_key})
|
759
465
|
return Main.result_success
|
760
|
-
when :
|
761
|
-
|
762
|
-
|
763
|
-
return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action if command.eql?(:v3)
|
764
|
-
ak_root_file_id = api_node.read("access_keys/#{res_data['access_key']}")[:data]['root_file_id']
|
765
|
-
command_repo = options.get_next_command(NODE4_COMMANDS)
|
766
|
-
return execute_node_gen4_command(command_repo,{node_info: res_data, file_id: ak_root_file_id})
|
767
|
-
when :shared_folder
|
768
|
-
Log.log.warn('ATTENTION: alpha, under development, do not use')
|
769
|
-
# inside a workspace
|
770
|
-
command_shared = options.get_next_command(%i[list create delete]) # member
|
771
|
-
core_api=Rest.new(aoc_api.params.merge(base_url: aoc_api.params[:base_url].gsub('/api.','/sedemo.')))
|
772
|
-
# generic permission created for each shared folder
|
773
|
-
access_id = "#{ID_AK_ADMIN}_WS_#{res_id}"
|
774
|
-
case command_shared
|
775
|
-
when :list
|
776
|
-
query=options.get_option(:query)
|
777
|
-
query={'admin' => true, 'access_id' => access_id, 'access_type' => 'user'} if query.nil?
|
778
|
-
res_data = aoc_api.read("#{resource_instance_path}/permissions",query)[:data]
|
779
|
-
return { type: :object_list, data: res_data, fields: %w[id node_id file_id node_name file.path tags.aspera.files.workspace.share_as access_id]}
|
780
|
-
when :member
|
781
|
-
#https://sedemo.ibmaspera.com/api/v1/node/8669/permissions_and_members/3270?inherited=false&aspera-node-basic=8669&admin=true&page=1&per_page=25
|
782
|
-
when :delete
|
783
|
-
shared_id=instance_identifier
|
784
|
-
all_shared=aoc_api.read("#{resource_instance_path}/permissions",query)[:data].select{|i|i['id'].eql?(shared_id)}
|
785
|
-
raise 'no such shared folder id' if all_shared.empty?
|
786
|
-
raise 'error' unless all_shared.length.eql?(1)
|
787
|
-
shared_info=all_shared.first
|
788
|
-
#return { type: :single_object, data: shared_info}
|
789
|
-
node_id=shared_info['node_id']
|
790
|
-
Log.log.warn('ATTENTION: under dev: user vars: V1 and V2')
|
791
|
-
core_api.call(
|
792
|
-
operation: 'DELETE',
|
793
|
-
subpath: "node/#{node_id}/permissions",
|
794
|
-
headers: {
|
795
|
-
'Accept' => 'application/json',
|
796
|
-
'aspera-node-auth' => ENV['V1'],
|
797
|
-
'aspera-node-tokens' => ENV['V2']
|
798
|
-
},
|
799
|
-
url_params: {
|
800
|
-
'ids' => shared_id,
|
801
|
-
'aspera-node-basic' => node_id,
|
802
|
-
'aspera-node-prefer-basic' => node_id
|
803
|
-
}
|
804
|
-
)
|
805
|
-
return Main.result_success
|
806
|
-
when :create
|
807
|
-
# workspace information
|
808
|
-
ws_info = aoc_api.read(resource_instance_path)[:data]
|
809
|
-
shared_create_data = options.get_next_argument('creation data',type: Hash)
|
810
|
-
# node is either provided by user, or by default the one of workspace
|
811
|
-
node_id = shared_create_data.has_key?('node_id') ? shared_create_data['node_id'] : ws_info['node_id']
|
812
|
-
# remove from creation data if present, as it is not a standard argument
|
813
|
-
shared_create_data.delete('node_id')
|
814
|
-
# get optional link_name
|
815
|
-
#opt_link_name=shared_create_data['link_name']
|
816
|
-
shared_create_data.delete('link_name')
|
817
|
-
raise 'missing node information: path' unless shared_create_data.has_key?('path')
|
818
|
-
folder_path=shared_create_data['path']
|
819
|
-
shared_create_data.delete('path')
|
820
|
-
node_file={node_info: aoc_api.read("nodes/#{node_id}")[:data], file_id: 1}
|
821
|
-
node_file = aoc_api.resolve_node_file(node_file,folder_path)
|
822
|
-
node_api = aoc_api.get_node_api(node_file[:node_info])
|
823
|
-
access_id = "#{ID_AK_ADMIN}_WS_#{ws_info['id']}"
|
824
|
-
# use can specify: tags.aspera.files.workspace.share_as to File.basename(folder_path)
|
825
|
-
default_create_data = {
|
826
|
-
'file_id' => node_file[:file_id],
|
827
|
-
'access_type' => 'user',
|
828
|
-
'access_id' => access_id,
|
829
|
-
'access_levels' => %w[list read write delete mkdir rename preview],
|
830
|
-
'tags' => {'aspera' => {'files' => {'workspace' => {
|
831
|
-
'id' => ws_info['id'],
|
832
|
-
'workspace_name' => ws_info['name'],
|
833
|
-
'user_name' => aoc_api.user_info['name'],
|
834
|
-
'shared_by_user_id' => aoc_api.user_info['id'],
|
835
|
-
'shared_by_name' => aoc_api.user_info['name'],
|
836
|
-
'shared_by_email' => aoc_api.user_info['email'],
|
837
|
-
'shared_with_name' => access_id,
|
838
|
-
'access_key' => node_file[:node_info]['access_key'],
|
839
|
-
'node' => node_file[:node_info]['name']}
|
840
|
-
}}}}
|
841
|
-
shared_create_data = default_create_data.deep_merge(default_create_data) # ?aspera-node-basic=#{node_id}&aspera-node-prefer-basic=#{node_id}
|
842
|
-
created_data = node_api.create('permissions',shared_create_data)[:data]
|
843
|
-
# new API:
|
844
|
-
#created_data=aoc_api.create("node/#{node_id}/permissions",shared_create_data)[:data]
|
845
|
-
# TODO: send event
|
846
|
-
event_creation={
|
847
|
-
'types' => ['permission.created'],
|
848
|
-
'node_id' => node_file[:node_info]['id'],
|
849
|
-
'workspace_id' => ws_info['id'],
|
850
|
-
'data' => created_data # Response from previous step
|
851
|
-
}
|
852
|
-
#(optional). The name of the folder to be displayed to the destination user. Use it if its value is different from the "share_as" field.
|
853
|
-
#event_creation['link_name']=opt_link_name unless opt_link_name.nil?
|
854
|
-
aoc_api.create('events',event_creation)
|
855
|
-
return { type: :single_object, data: created_data}
|
856
|
-
end
|
466
|
+
when :do
|
467
|
+
command_repo = options.get_next_command(NODE4_EXT_COMMANDS)
|
468
|
+
return execute_nodegen4_command(command_repo, res_id)
|
857
469
|
else raise 'unknown command'
|
858
470
|
end
|
859
471
|
when :usage_reports
|
860
|
-
return {type: :object_list,data: aoc_api.read('usage_reports',{workspace_id:
|
472
|
+
return {type: :object_list, data: aoc_api.read('usage_reports', {workspace_id: current_workspace_info['id']})[:data]}
|
861
473
|
end
|
862
474
|
end
|
863
475
|
|
@@ -869,13 +481,13 @@ module Aspera
|
|
869
481
|
case command
|
870
482
|
when :reminder
|
871
483
|
# send an email reminder with list of orgs
|
872
|
-
user_email = options.get_option(:username,is_type: :mandatory)
|
873
|
-
Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders',{email: user_email})[:data]
|
484
|
+
user_email = options.get_option(:username, is_type: :mandatory)
|
485
|
+
Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders', {email: user_email})[:data]
|
874
486
|
return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
|
875
487
|
when :servers
|
876
|
-
return {type: :object_list,data: Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
|
488
|
+
return {type: :object_list, data: Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
|
877
489
|
when :bearer_token
|
878
|
-
return {type: :text,data: aoc_api.oauth_token}
|
490
|
+
return {type: :text, data: aoc_api.oauth_token}
|
879
491
|
when :organization
|
880
492
|
return { type: :single_object, data: aoc_api.read('organization')[:data] }
|
881
493
|
when :tier_restrictions
|
@@ -887,116 +499,103 @@ module Aspera
|
|
887
499
|
when :workspaces
|
888
500
|
case options.get_next_command(%i[list current])
|
889
501
|
when :list
|
890
|
-
return {type: :object_list,data: aoc_api.read('workspaces')[:data],fields: %w[id name]}
|
502
|
+
return {type: :object_list, data: aoc_api.read('workspaces')[:data], fields: %w[id name]}
|
891
503
|
when :current
|
892
|
-
|
893
|
-
return { type: :single_object, data: @workspace_info }
|
504
|
+
return { type: :single_object, data: current_workspace_info }
|
894
505
|
end
|
895
506
|
when :profile
|
896
507
|
case options.get_next_command(%i[show modify])
|
897
508
|
when :show
|
898
|
-
return { type: :single_object, data: aoc_api.
|
509
|
+
return { type: :single_object, data: aoc_api.current_user_info(exception: true) }
|
899
510
|
when :modify
|
900
|
-
aoc_api.update("users/#{aoc_api.
|
511
|
+
aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}", options.get_next_argument('modified parameters (hash)'))
|
901
512
|
return Main.result_status('modified')
|
902
513
|
end
|
903
514
|
end
|
904
515
|
when :packages
|
905
|
-
|
906
|
-
package_command = options.get_next_command([%i[shared_inboxes send recv list show delete],NODE4_CMD_PATH].flatten)
|
516
|
+
package_command = options.get_next_command(%i[shared_inboxes send recv list show delete].concat(Node::NODE4_READ_ACTIONS))
|
907
517
|
case package_command
|
908
518
|
when :shared_inboxes
|
909
519
|
case options.get_next_command(%i[list show])
|
910
520
|
when :list
|
911
521
|
query = option_url_query(nil)
|
912
522
|
if query.nil?
|
913
|
-
query = {'embed[]' => 'dropbox','aggregate_permissions_by_dropbox' => true,'sort' => 'dropbox_name'}
|
914
|
-
query['workspace_id']
|
523
|
+
query = {'embed[]' => 'dropbox', 'aggregate_permissions_by_dropbox' => true, 'sort' => 'dropbox_name'}
|
524
|
+
query['workspace_id'] = current_workspace_info['id'] unless current_workspace_info['id'].eql?(:undefined)
|
915
525
|
end
|
916
|
-
return {type: :object_list,data: aoc_api.read('dropbox_memberships',query)[:data],fields: ['dropbox_id','dropbox.name']}
|
526
|
+
return {type: :object_list, data: aoc_api.read('dropbox_memberships', query)[:data], fields: ['dropbox_id', 'dropbox.name']}
|
917
527
|
when :show
|
918
|
-
return {type: :single_object,data: aoc_api.read(get_resource_path_from_args('dropboxes'),query)[:data]}
|
528
|
+
return {type: :single_object, data: aoc_api.read(get_resource_path_from_args('dropboxes'), query)[:data]}
|
919
529
|
end
|
920
530
|
when :send
|
921
|
-
package_data = options.get_option(:value,is_type: :mandatory)
|
922
|
-
raise CliBadArgument,'value must be hash, refer to doc' unless package_data.is_a?(Hash)
|
923
|
-
|
924
|
-
|
531
|
+
package_data = options.get_option(:value, is_type: :mandatory)
|
532
|
+
raise CliBadArgument, 'value must be hash, refer to doc' unless package_data.is_a?(Hash)
|
533
|
+
new_user_option = options.get_option(:new_user_option)
|
534
|
+
option_validate = options.get_option(:validate_metadata)
|
535
|
+
# works for both normal usr auth and link auth
|
536
|
+
package_data['workspace_id'] ||= current_workspace_info['id']
|
537
|
+
|
538
|
+
if !aoc_api.url_token_data.nil?
|
925
539
|
assert_public_link_types(%w[send_package_to_user send_package_to_dropbox])
|
926
|
-
box_type =
|
927
|
-
package_data['recipients'] = [{'id' =>
|
928
|
-
#
|
929
|
-
|
540
|
+
box_type = aoc_api.url_token_data['purpose'].split('_').last
|
541
|
+
package_data['recipients'] = [{'id' => aoc_api.url_token_data['data']["#{box_type}_id"], 'type' => box_type}]
|
542
|
+
# enforce workspace id from link (should be already ok, but in case user wanted to override)
|
543
|
+
package_data['workspace_id'] = aoc_api.url_token_data['data']['workspace_id']
|
930
544
|
end
|
931
545
|
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
#
|
936
|
-
|
937
|
-
# lookup users
|
938
|
-
resolve_package_recipients(package_data,'recipients')
|
939
|
-
resolve_package_recipients(package_data,'bcc_recipients')
|
940
|
-
normalize_metadata(package_data)
|
941
|
-
validate_metadata(package_data) if options.get_option(:validate_metadata)
|
942
|
-
|
943
|
-
# create a new package container
|
944
|
-
package_info = aoc_api.create('packages',package_data)[:data]
|
945
|
-
|
946
|
-
# get node information for the node on which package must be created
|
947
|
-
node_info = aoc_api.read("nodes/#{package_info['node_id']}")[:data]
|
948
|
-
|
949
|
-
# tell AoC what to expect in package: 1 transfer (can also be done after transfer)
|
950
|
-
# TODO: if multisession was used we should probably tell
|
951
|
-
# also, currently no "multi-source" , i.e. only from client-side files, unless "node" agent is used
|
952
|
-
aoc_api.update("packages/#{package_info['id']}",{'sent' => true,'transfers_expected' => 1})[:data]
|
953
|
-
|
954
|
-
# get destination: package folder
|
955
|
-
node_file = {node_info: node_info, file_id: package_info['contents_file_id']}
|
956
|
-
# execute transfer, raise exception if at least one error
|
957
|
-
Main.result_transfer(transfer_start(AoC::PACKAGES_APP,Fasp::TransferSpec::DIRECTION_SEND,node_file,AoC.package_tags(package_info,'upload')))
|
958
|
-
# return all info on package
|
959
|
-
return { type: :single_object, data: package_info}
|
546
|
+
# transfer may raise an error
|
547
|
+
created_package = aoc_api.create_package_simple(package_data, option_validate, new_user_option)
|
548
|
+
Main.result_transfer(transfer.start(created_package[:spec], rest_token: created_package[:node]))
|
549
|
+
# return all info on package (especially package id)
|
550
|
+
return { type: :single_object, data: created_package[:info]}
|
960
551
|
when :recv
|
961
|
-
if
|
552
|
+
if !aoc_api.url_token_data.nil?
|
962
553
|
assert_public_link_types(['view_received_package'])
|
963
|
-
options.set_option(:id
|
554
|
+
options.set_option(:id, aoc_api.url_token_data['data']['package_id'])
|
964
555
|
end
|
965
556
|
# scalar here
|
966
557
|
ids_to_download = instance_identifier
|
967
558
|
skip_ids_data = []
|
968
559
|
skip_ids_persistency = nil
|
969
|
-
if options.get_option(:once_only,is_type: :mandatory)
|
560
|
+
if options.get_option(:once_only, is_type: :mandatory)
|
970
561
|
skip_ids_persistency = PersistencyActionOnce.new(
|
971
562
|
manager: @agents[:persistency],
|
972
563
|
data: skip_ids_data,
|
973
|
-
id: IdGenerator.from_list(['aoc_recv',options.get_option(:url,is_type: :mandatory)
|
564
|
+
id: IdGenerator.from_list(['aoc_recv', options.get_option(:url, is_type: :mandatory),
|
565
|
+
current_workspace_info['id']].concat(aoc_api.additional_persistence_ids)))
|
974
566
|
end
|
975
|
-
if
|
567
|
+
if VAL_ALL.eql?(ids_to_download)
|
568
|
+
query = option_url_query(PACKAGE_QUERY_DEFAULT)
|
569
|
+
raise 'option query must be Hash' unless query.is_a?(Hash)
|
570
|
+
if query.key?('dropbox_name')
|
571
|
+
# convenience: specify name instead of id
|
572
|
+
raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
|
573
|
+
query['dropbox_id'] = aoc_api.lookup_entity_by_name('dropboxes', query['dropbox_name'])['id']
|
574
|
+
query.delete('dropbox_name')
|
575
|
+
end
|
576
|
+
query['workspace_id'] ||= current_workspace_info['id'] unless current_workspace_info['id'].eql?(:undefined)
|
976
577
|
# get list of packages in inbox
|
977
|
-
package_info = aoc_api.read('packages',
|
978
|
-
'archived' => false,
|
979
|
-
'exclude_dropbox_packages' => true,
|
980
|
-
'has_content' => true,
|
981
|
-
'received' => true,
|
982
|
-
'workspace_id' => @workspace_info['id']})[:data]
|
578
|
+
package_info = aoc_api.read('packages', query)[:data]
|
983
579
|
# remove from list the ones already downloaded
|
984
580
|
ids_to_download = package_info.map{|e|e['id']}
|
985
581
|
# array here
|
986
582
|
ids_to_download.reject!{|id|skip_ids_data.include?(id)}
|
987
|
-
end #
|
583
|
+
end # VAL_ALL
|
988
584
|
# list here
|
989
585
|
ids_to_download = [ids_to_download] unless ids_to_download.is_a?(Array)
|
990
586
|
result_transfer = []
|
991
|
-
|
587
|
+
formatter.display_status("found #{ids_to_download.length} package(s).")
|
992
588
|
ids_to_download.each do |package_id|
|
993
589
|
package_info = aoc_api.read("packages/#{package_id}")[:data]
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
590
|
+
formatter.display_status("downloading package: #{package_info['name']}")
|
591
|
+
package_node_api = aoc_api.node_api_from(package_info: package_info, scope: AoC::SCOPE_NODE_USER)
|
592
|
+
statuses = transfer.start(
|
593
|
+
package_node_api.transfer_spec_gen4(
|
594
|
+
package_info['contents_file_id'],
|
595
|
+
Fasp::TransferSpec::DIRECTION_RECEIVE,
|
596
|
+
{'paths'=> [{'source' => '.'}]}),
|
597
|
+
rest_token: package_node_api)
|
598
|
+
result_transfer.push({'package' => package_id, Main::STATUS_FIELD => statuses})
|
1000
599
|
# update skip list only if all transfer sessions completed
|
1001
600
|
if TransferAgent.session_status(statuses).eql?(:success)
|
1002
601
|
skip_ids_data.push(package_id)
|
@@ -1009,62 +608,57 @@ module Aspera
|
|
1009
608
|
package_info = aoc_api.read("packages/#{package_id}")[:data]
|
1010
609
|
return { type: :single_object, data: package_info }
|
1011
610
|
when :list
|
1012
|
-
display_fields
|
1013
|
-
query = option_url_query(
|
1014
|
-
|
611
|
+
display_fields = %w[id name bytes_transferred]
|
612
|
+
query = option_url_query(PACKAGE_QUERY_DEFAULT)
|
613
|
+
raise 'option query must be Hash' unless query.is_a?(Hash)
|
614
|
+
if query.key?('dropbox_name')
|
1015
615
|
# convenience: specify name instead of id
|
1016
|
-
raise 'not both dropbox_name and dropbox_id' if query.
|
1017
|
-
query['dropbox_id'] = aoc_api.lookup_entity_by_name('dropboxes',query['dropbox_name'])['id']
|
616
|
+
raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
|
617
|
+
query['dropbox_id'] = aoc_api.lookup_entity_by_name('dropboxes', query['dropbox_name'])['id']
|
1018
618
|
query.delete('dropbox_name')
|
1019
619
|
end
|
1020
|
-
|
1021
|
-
if @workspace_info['id'].eql?(:undefined)
|
620
|
+
if current_workspace_info['id'].eql?(:undefined)
|
1022
621
|
display_fields.push('workspace_id')
|
1023
622
|
else
|
1024
|
-
query['workspace_id'] ||=
|
623
|
+
query['workspace_id'] ||= current_workspace_info['id']
|
1025
624
|
end
|
1026
|
-
packages = aoc_api.read('packages',query)[:data]
|
1027
|
-
return {type: :object_list,data: packages,fields: display_fields}
|
625
|
+
packages = aoc_api.read('packages', query)[:data]
|
626
|
+
return {type: :object_list, data: packages, fields: display_fields}
|
1028
627
|
when :delete
|
1029
628
|
list_or_one = instance_identifier
|
1030
|
-
return do_bulk_operation(list_or_one,'deleted') do |id|
|
629
|
+
return do_bulk_operation(list_or_one, 'deleted') do |id|
|
1031
630
|
raise 'expecting String identifier' unless id.is_a?(String) || id.is_a?(Integer)
|
1032
631
|
aoc_api.delete("packages/#{id}")[:data]
|
1033
632
|
end
|
1034
|
-
when *
|
633
|
+
when *Node::NODE4_READ_ACTIONS
|
1035
634
|
package_id = options.get_next_argument('package ID')
|
1036
|
-
#path = options.get_next_argument('path', mandatory: false) || '/'
|
1037
635
|
package_info = aoc_api.read("packages/#{package_id}")[:data]
|
1038
|
-
|
1039
|
-
node_info: aoc_api.read("nodes/#{package_info['node_id']}")[:data],
|
1040
|
-
file_id: package_info['file_id']
|
1041
|
-
}
|
1042
|
-
return execute_node_gen4_command(package_command,package_node_file)
|
636
|
+
return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['file_id'], scope: AoC::SCOPE_NODE_USER)
|
1043
637
|
end
|
1044
638
|
when :files
|
1045
|
-
|
1046
|
-
set_workspace_info
|
1047
|
-
set_home_node_file
|
1048
|
-
command_repo = options.get_next_command([NODE4_COMMANDS,:short_link].flatten)
|
639
|
+
command_repo = options.get_next_command([:short_link].concat(NODE4_EXT_COMMANDS))
|
1049
640
|
case command_repo
|
1050
|
-
when *
|
641
|
+
when *NODE4_EXT_COMMANDS
|
642
|
+
return execute_nodegen4_command(command_repo, home_info[:node_id], file_id: home_info[:file_id], scope: AoC::SCOPE_NODE_USER)
|
1051
643
|
when :short_link
|
644
|
+
# TODO: move to permissions ?
|
1052
645
|
folder_dest = options.get_option(:to_folder)
|
1053
646
|
value_option = options.get_option(:value)
|
1054
647
|
case value_option
|
1055
648
|
when 'public' then value_option = {'purpose' => 'token_auth_redirection'}
|
1056
649
|
when 'private' then value_option = {'purpose' => 'shared_folder_auth_link'}
|
1057
|
-
when NilClass,Hash then nil # keep value
|
650
|
+
when NilClass, Hash then nil # keep value
|
1058
651
|
else raise 'value must be either: public, private, Hash or nil'
|
1059
652
|
end
|
1060
653
|
create_params = nil
|
1061
|
-
|
654
|
+
shared_apfid = nil
|
1062
655
|
if !folder_dest.nil?
|
1063
|
-
|
656
|
+
home_node_api = aoc_api.node_api_from(node_id: home_info[:node_id], workspace_info: current_workspace_info, scope: AoC::SCOPE_NODE_USER)
|
657
|
+
shared_apfid = home_node_api.resolve_api_fid(home_info[:file_id], folder_dest)
|
1064
658
|
create_params = {
|
1065
|
-
file_id:
|
1066
|
-
node_id:
|
1067
|
-
workspace_id:
|
659
|
+
file_id: shared_apfid[:file_id],
|
660
|
+
node_id: shared_apfid[:api].app_info[:node_info]['id'],
|
661
|
+
workspace_id: current_workspace_info['id']
|
1068
662
|
}
|
1069
663
|
end
|
1070
664
|
if !value_option.nil? && !create_params.nil?
|
@@ -1085,30 +679,29 @@ module Aspera
|
|
1085
679
|
else
|
1086
680
|
raise 'purpose must be one of: token_auth_redirection or shared_folder_auth_link'
|
1087
681
|
end
|
1088
|
-
options.set_option(:value,value_option)
|
682
|
+
options.set_option(:value, value_option)
|
1089
683
|
end
|
1090
|
-
result = entity_action(
|
1091
|
-
if result[:data].is_a?(Hash) && result[:data].
|
1092
|
-
node_api = aoc_api.get_node_api(node_file[:node_info])
|
684
|
+
result = entity_action(aoc_api, 'short_links', id_default: 'self')
|
685
|
+
if result[:data].is_a?(Hash) && result[:data].key?('created_at') && result[:data]['resource_type'].eql?('UrlToken')
|
1093
686
|
# TODO: access level as arg
|
1094
|
-
access_levels = Aspera::Node::ACCESS_LEVELS #['delete','list','mkdir','preview','read','rename','write']
|
687
|
+
access_levels = Aspera::Node::ACCESS_LEVELS # ['delete','list','mkdir','preview','read','rename','write']
|
1095
688
|
perm_data = {
|
1096
|
-
'file_id' =>
|
689
|
+
'file_id' => shared_apfid[:file_id],
|
1097
690
|
'access_type' => 'user',
|
1098
691
|
'access_id' => result[:data]['resource_id'],
|
1099
692
|
'access_levels' => access_levels,
|
1100
693
|
'tags' => {
|
1101
694
|
'url_token' => true,
|
1102
|
-
'workspace_id' =>
|
1103
|
-
'workspace_name' =>
|
695
|
+
'workspace_id' => current_workspace_info['id'],
|
696
|
+
'workspace_name' => current_workspace_info['name'],
|
1104
697
|
'folder_name' => 'my folder',
|
1105
|
-
'created_by_name' => aoc_api.
|
1106
|
-
'created_by_email' => aoc_api.
|
1107
|
-
'access_key' =>
|
1108
|
-
'node' =>
|
698
|
+
'created_by_name' => aoc_api.current_user_info['name'],
|
699
|
+
'created_by_email' => aoc_api.current_user_info['email'],
|
700
|
+
'access_key' => shared_apfid[:api].app_info[:node_info]['access_key'],
|
701
|
+
'node' => shared_apfid[:api].app_info[:node_info]['host']
|
1109
702
|
}
|
1110
703
|
}
|
1111
|
-
|
704
|
+
shared_apfid[:api].create("permissions?file_id=#{shared_apfid[:file_id]}", perm_data)
|
1112
705
|
# TODO: event ?
|
1113
706
|
end
|
1114
707
|
return result
|
@@ -1118,49 +711,58 @@ module Aspera
|
|
1118
711
|
Log.log.warn('BETA: work under progress')
|
1119
712
|
# automation api is not in the same place
|
1120
713
|
automation_rest_params = aoc_api.params.clone
|
1121
|
-
automation_rest_params[:base_url].gsub!('/api/','/automation/')
|
714
|
+
automation_rest_params[:base_url].gsub!('/api/', '/automation/')
|
1122
715
|
automation_api = Rest.new(automation_rest_params)
|
1123
716
|
command_automation = options.get_next_command(%i[workflows instances])
|
1124
717
|
case command_automation
|
1125
718
|
when :instances
|
1126
|
-
return entity_action(
|
719
|
+
return entity_action(aoc_api, 'workflow_instances')
|
1127
720
|
when :workflows
|
1128
|
-
wf_command = options.get_next_command([
|
721
|
+
wf_command = options.get_next_command(%i[action launch].concat(Plugin::ALL_OPS))
|
1129
722
|
case wf_command
|
1130
723
|
when *Plugin::ALL_OPS
|
1131
|
-
return entity_command(wf_command,automation_api,'workflows',id_default: :id)
|
724
|
+
return entity_command(wf_command, automation_api, 'workflows', id_default: :id)
|
1132
725
|
when :launch
|
1133
726
|
wf_id = instance_identifier
|
1134
|
-
data = automation_api.create("workflows/#{wf_id}/launch",{})[:data]
|
1135
|
-
return {type: :single_object,data: data}
|
727
|
+
data = automation_api.create("workflows/#{wf_id}/launch", {})[:data]
|
728
|
+
return {type: :single_object, data: data}
|
1136
729
|
when :action
|
1137
|
-
#TODO: not complete
|
730
|
+
# TODO: not complete
|
1138
731
|
wf_id = instance_identifier
|
1139
732
|
wf_action_cmd = options.get_next_command(%i[list create show])
|
1140
|
-
Log.log.warn
|
1141
|
-
step = automation_api.create('steps',{'workflow_id' => wf_id})[:data]
|
1142
|
-
automation_api.update("workflows/#{wf_id}",{'step_order' => [step['id']]})
|
1143
|
-
action = automation_api.create('actions',{'step_id' => step['id'],'type' => 'manual'})[:data]
|
1144
|
-
automation_api.update("steps/#{step['id']}",{'action_order' => [action['id']]})
|
733
|
+
Log.log.warn{"Not implemented: #{wf_action_cmd}"}
|
734
|
+
step = automation_api.create('steps', {'workflow_id' => wf_id})[:data]
|
735
|
+
automation_api.update("workflows/#{wf_id}", {'step_order' => [step['id']]})
|
736
|
+
action = automation_api.create('actions', {'step_id' => step['id'], 'type' => 'manual'})[:data]
|
737
|
+
automation_api.update("steps/#{step['id']}", {'action_order' => [action['id']]})
|
1145
738
|
wf = automation_api.read("workflows/#{wf_id}")[:data]
|
1146
|
-
return {type: :single_object,data: wf}
|
739
|
+
return {type: :single_object, data: wf}
|
1147
740
|
end
|
1148
741
|
end
|
1149
742
|
when :admin
|
1150
743
|
return execute_admin_action
|
1151
744
|
when :gateway
|
1152
|
-
set_workspace_info
|
1153
745
|
require 'aspera/faspex_gw'
|
1154
|
-
|
746
|
+
url = options.get_option(:value, is_type: :mandatory)
|
747
|
+
uri = URI.parse(url)
|
748
|
+
server = WebServerSimple.new(uri)
|
749
|
+
server.mount(uri.path, Faspex4GWServlet, aoc_api, current_workspace_info['id'])
|
750
|
+
trap('INT') { server.shutdown }
|
751
|
+
formatter.display_status("Faspex 4 gateway listening on #{url}")
|
752
|
+
Log.log.info("Listening on #{url}")
|
753
|
+
# this is blocking until server exits
|
754
|
+
server.start
|
755
|
+
return Main.result_status('Gateway terminated')
|
1155
756
|
else
|
1156
757
|
raise "internal error: #{command}"
|
1157
758
|
end # action
|
1158
759
|
raise 'internal error: command shall return'
|
1159
760
|
end
|
1160
761
|
|
1161
|
-
private :aoc_params
|
762
|
+
private :aoc_params,
|
763
|
+
:home_info,
|
764
|
+
:assert_public_link_types,
|
1162
765
|
:execute_admin_action
|
1163
|
-
private_constant :VAL_ALL,:NODE4_COMMANDS, :ID_AK_ADMIN
|
1164
766
|
end # AoC
|
1165
767
|
end # Plugins
|
1166
768
|
end # Cli
|