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