aspera-cli 4.10.0 → 4.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +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
|