aspera-cli 4.9.0 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +20 -0
  4. data/CHANGELOG.md +509 -0
  5. data/CONTRIBUTING.md +118 -0
  6. data/README.md +1241 -916
  7. data/bin/ascli +4 -4
  8. data/bin/asession +11 -11
  9. data/docs/test_env.conf +32 -21
  10. data/examples/aoc.rb +4 -4
  11. data/examples/dascli +16 -9
  12. data/examples/faspex4.rb +8 -8
  13. data/examples/node.rb +12 -12
  14. data/examples/server.rb +10 -10
  15. data/lib/aspera/aoc.rb +273 -266
  16. data/lib/aspera/ascmd.rb +56 -54
  17. data/lib/aspera/ats_api.rb +4 -4
  18. data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
  19. data/lib/aspera/cli/extended_value.rb +5 -5
  20. data/lib/aspera/cli/formater.rb +64 -64
  21. data/lib/aspera/cli/info.rb +2 -2
  22. data/lib/aspera/cli/listener/line_dump.rb +1 -1
  23. data/lib/aspera/cli/listener/logger.rb +1 -1
  24. data/lib/aspera/cli/listener/progress.rb +5 -6
  25. data/lib/aspera/cli/listener/progress_multi.rb +14 -19
  26. data/lib/aspera/cli/main.rb +66 -67
  27. data/lib/aspera/cli/manager.rb +112 -110
  28. data/lib/aspera/cli/plugin.rb +57 -36
  29. data/lib/aspera/cli/plugins/alee.rb +4 -4
  30. data/lib/aspera/cli/plugins/aoc.rb +309 -670
  31. data/lib/aspera/cli/plugins/ats.rb +44 -46
  32. data/lib/aspera/cli/plugins/bss.rb +10 -10
  33. data/lib/aspera/cli/plugins/config.rb +497 -378
  34. data/lib/aspera/cli/plugins/console.rb +12 -12
  35. data/lib/aspera/cli/plugins/cos.rb +18 -20
  36. data/lib/aspera/cli/plugins/faspex.rb +112 -114
  37. data/lib/aspera/cli/plugins/faspex5.rb +71 -46
  38. data/lib/aspera/cli/plugins/node.rb +379 -283
  39. data/lib/aspera/cli/plugins/orchestrator.rb +46 -46
  40. data/lib/aspera/cli/plugins/preview.rb +122 -114
  41. data/lib/aspera/cli/plugins/server.rb +137 -83
  42. data/lib/aspera/cli/plugins/shares.rb +30 -29
  43. data/lib/aspera/cli/plugins/sync.rb +13 -33
  44. data/lib/aspera/cli/transfer_agent.rb +60 -59
  45. data/lib/aspera/cli/version.rb +1 -1
  46. data/lib/aspera/colors.rb +3 -3
  47. data/lib/aspera/command_line_builder.rb +27 -27
  48. data/lib/aspera/cos_node.rb +22 -20
  49. data/lib/aspera/data_repository.rb +1 -1
  50. data/lib/aspera/environment.rb +35 -15
  51. data/lib/aspera/fasp/agent_base.rb +15 -15
  52. data/lib/aspera/fasp/agent_connect.rb +23 -21
  53. data/lib/aspera/fasp/agent_direct.rb +66 -64
  54. data/lib/aspera/fasp/agent_httpgw.rb +141 -78
  55. data/lib/aspera/fasp/agent_node.rb +23 -21
  56. data/lib/aspera/fasp/agent_trsdk.rb +20 -20
  57. data/lib/aspera/fasp/error.rb +3 -2
  58. data/lib/aspera/fasp/error_info.rb +11 -8
  59. data/lib/aspera/fasp/installation.rb +79 -79
  60. data/lib/aspera/fasp/listener.rb +1 -1
  61. data/lib/aspera/fasp/parameters.rb +86 -71
  62. data/lib/aspera/fasp/parameters.yaml +7 -4
  63. data/lib/aspera/fasp/resume_policy.rb +8 -8
  64. data/lib/aspera/fasp/transfer_spec.rb +35 -2
  65. data/lib/aspera/fasp/uri.rb +7 -7
  66. data/lib/aspera/faspex_gw.rb +7 -5
  67. data/lib/aspera/hash_ext.rb +3 -3
  68. data/lib/aspera/id_generator.rb +5 -5
  69. data/lib/aspera/keychain/encrypted_hash.rb +38 -105
  70. data/lib/aspera/keychain/macos_security.rb +128 -57
  71. data/lib/aspera/log.rb +7 -7
  72. data/lib/aspera/nagios.rb +19 -18
  73. data/lib/aspera/node.rb +209 -35
  74. data/lib/aspera/oauth.rb +37 -36
  75. data/lib/aspera/open_application.rb +19 -11
  76. data/lib/aspera/persistency_action_once.rb +4 -4
  77. data/lib/aspera/persistency_folder.rb +16 -15
  78. data/lib/aspera/preview/file_types.rb +8 -8
  79. data/lib/aspera/preview/generator.rb +67 -67
  80. data/lib/aspera/preview/utils.rb +27 -27
  81. data/lib/aspera/proxy_auto_config.js +41 -41
  82. data/lib/aspera/proxy_auto_config.rb +21 -14
  83. data/lib/aspera/rest.rb +72 -67
  84. data/lib/aspera/rest_call_error.rb +2 -1
  85. data/lib/aspera/rest_error_analyzer.rb +18 -17
  86. data/lib/aspera/rest_errors_aspera.rb +16 -16
  87. data/lib/aspera/secret_hider.rb +15 -13
  88. data/lib/aspera/ssh.rb +11 -10
  89. data/lib/aspera/sync.rb +158 -44
  90. data/lib/aspera/temp_file_manager.rb +2 -2
  91. data/lib/aspera/uri_reader.rb +4 -4
  92. data/lib/aspera/web_auth.rb +14 -13
  93. data.tar.gz.sig +0 -0
  94. metadata +11 -36
  95. metadata.gz.sig +0 -0
@@ -16,334 +16,94 @@ 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
- 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
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'
38
54
 
39
55
  def initialize(env)
40
56
  super(env)
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
47
- options.add_opt_list(:auth,Oauth::STD_AUTH_TYPES,'OAuth type of authentication')
48
- options.add_opt_list(:operation, %i[push pull],'client operation for transfers')
49
- options.add_opt_simple(:client_id,'OAuth API client identifier in application')
50
- options.add_opt_simple(:client_secret,'OAuth API client passcode')
51
- options.add_opt_simple(:redirect_uri,'OAuth API client redirect URI')
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')
54
- options.add_opt_simple(:workspace,'name of workspace')
55
- options.add_opt_simple(:name,'resource name')
56
- options.add_opt_simple(:path,'file or folder path')
57
- options.add_opt_simple(:link,'public link to shared resource')
58
- options.add_opt_simple(:new_user_option,'new user creation option for unknown package recipients')
59
- options.add_opt_simple(:from_folder,'share to share source folder')
60
- options.add_opt_simple(:scope,'OAuth scope for AoC API calls')
61
- options.add_opt_boolean(:default_ports,'use standard FASP ports or get from node api')
62
- options.add_opt_boolean(:validate_metadata,'validate shared inbox metadata')
63
- options.set_option(:default_ports,:yes)
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)
57
+ @cache_workspace_info = nil
58
+ @cache_home_node_file = nil
59
+ @cache_api_aoc = nil
60
+ options.add_opt_list(:auth, Oauth::STD_AUTH_TYPES, 'OAuth type of authentication')
61
+ options.add_opt_list(:operation, %i[push pull], 'client operation for transfers')
62
+ options.add_opt_simple(:client_id, 'OAuth API client identifier in application')
63
+ options.add_opt_simple(:client_secret, 'OAuth API client passcode')
64
+ options.add_opt_simple(:redirect_uri, 'OAuth API client redirect URI')
65
+ options.add_opt_simple(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
66
+ options.add_opt_simple(:scope, 'OAuth scope for AoC API calls')
67
+ options.add_opt_simple(:passphrase, 'RSA private key passphrase')
68
+ options.add_opt_simple(:workspace, 'Name of workspace')
69
+ options.add_opt_simple(:name, "Resource name (prefer to use keyword #{ENTITY_NAME_SPECIFIER})")
70
+ options.add_opt_simple(:link, 'Public link to shared resource')
71
+ options.add_opt_simple(:new_user_option, 'New user creation option for unknown package recipients')
72
+ options.add_opt_simple(:from_folder, 'Source folder for Folder-to-Folder transfer')
73
+ options.add_opt_boolean(:validate_metadata, 'Validate shared inbox metadata')
74
+ options.set_option(:validate_metadata, :yes)
75
+ options.set_option(:operation, :push)
76
+ options.set_option(:auth, :jwt)
77
+ options.set_option(:scope, AoC::SCOPE_FILES_USER)
78
+ options.set_option(:private_key, '@file:' + env[:private_key_path]) if env[:private_key_path].is_a?(String)
79
+ options.set_option(:workspace, :default)
71
80
  options.parse_options!
72
- AoC.use_standard_ports = options.get_option(:default_ports)
73
- return if env[:man_only]
81
+ # add node plugin options
82
+ Node.new(env.merge({man_only: true, skip_basic_auth_options: true}))
83
+ end
84
+
85
+ # build list of options for AoC API, based on options of CLI
86
+ def aoc_params(subpath)
87
+ # copy command line options to args
88
+ return Aspera::AoC::OPTIONS_NEW.each_with_object({subpath: subpath}){|i, m|m[i] = options.get_option(i)}
74
89
  end
75
90
 
76
91
  def aoc_api
77
- if @api_aoc.nil?
78
- @api_aoc = AoC.new(aoc_params(AoC::API_V1))
92
+ if @cache_api_aoc.nil?
93
+ @cache_api_aoc = AoC.new(aoc_params(AoC::API_V1))
79
94
  # add keychain for access key secrets
80
- @api_aoc.key_chain = @agents[:config]
95
+ @cache_api_aoc.secret_finder = @agents[:config]
81
96
  end
82
- return @api_aoc
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
97
+ return @cache_api_aoc
332
98
  end
333
99
 
334
- # initialize apis and authentication
335
- # set:
336
- # @workspace_info
337
- # @persist_ids
338
- # returns nil
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']]
100
+ # @return [Hash] current workspace information,
101
+ def current_workspace_info
102
+ return @cache_workspace_info unless @cache_workspace_info.nil?
103
+ default_workspace_id = if aoc_api.url_token_data.nil?
104
+ aoc_api.user_info['default_workspace_id']
344
105
  else
345
- default_workspace_id = @url_token_data['data']['workspace_id']
346
- @persist_ids = [] # TODO : @url_token_data['id'] ?
106
+ aoc_api.url_token_data['data']['workspace_id']
347
107
  end
348
108
 
349
109
  ws_name = options.get_option(:workspace)
@@ -351,42 +111,42 @@ module Aspera
351
111
  case ws_name
352
112
  when :default
353
113
  Log.log.debug('Using default workspace'.green)
354
- raise CliError,'No default workspace defined for user, please specify workspace' if default_workspace_id.nil?
114
+ raise CliError, 'No default workspace defined for user, please specify workspace' if default_workspace_id.nil?
355
115
  default_workspace_id
356
- when String then aoc_api.lookup_entity_by_name('workspaces',ws_name)['id']
116
+ when String then aoc_api.lookup_entity_by_name('workspaces', ws_name)['id']
357
117
  when NilClass then nil
358
- else raise CliError,'unexpected value type for workspace'
118
+ else raise CliError, 'unexpected value type for workspace'
359
119
  end
360
- @workspace_info =
120
+ @cache_workspace_info =
361
121
  begin
362
122
  aoc_api.read("workspaces/#{ws_id}")[:data]
363
123
  rescue Aspera::RestCallError => e
364
124
  Log.log.debug(e.message)
365
125
  { 'id' => :undefined, 'name' => :undefined }
366
126
  end
367
- Log.dump(:workspace_data,@workspace_info)
127
+ Log.dump(:current_workspace_info, @cache_workspace_info)
368
128
  # display workspace
369
- self.format.display_status("Current Workspace: #{@workspace_info['name'].to_s.red}#{@workspace_info['id'] == default_workspace_id ? ' (default)' : ''}")
370
- return nil
129
+ default_flag = @cache_workspace_info['id'] == default_workspace_id ? ' (default)' : ''
130
+ self.format.display_status("Current Workspace: #{@cache_workspace_info['name'].to_s.red}#{default_flag}")
131
+ return @cache_workspace_info
371
132
  end
372
133
 
373
- # @home_node_file (hash with :node_info and :file_id)
374
- def set_home_node_file
375
- if !@url_token_data.nil?
134
+ # @return [Hash] with :node_id and :file_id
135
+ def home_info
136
+ return @cache_home_node_file unless @cache_home_node_file.nil?
137
+ if !aoc_api.url_token_data.nil?
376
138
  assert_public_link_types(['view_shared_file'])
377
- home_node_id = @url_token_data['data']['node_id']
378
- home_file_id = @url_token_data['data']['file_id']
139
+ home_node_id = aoc_api.url_token_data['data']['node_id']
140
+ home_file_id = aoc_api.url_token_data['data']['file_id']
379
141
  end
380
- home_node_id ||= @workspace_info['home_node_id'] || @workspace_info['node_id']
381
- home_file_id ||= @workspace_info['home_file_id']
142
+ home_node_id ||= current_workspace_info['home_node_id'] || current_workspace_info['node_id']
143
+ home_file_id ||= current_workspace_info['home_file_id']
382
144
  raise "Cannot get user's home node id, check your default workspace or specify one" if home_node_id.to_s.empty?
383
- @home_node_file = {
384
- node_info: aoc_api.read("nodes/#{home_node_id}")[:data],
385
- file_id: home_file_id
145
+ @cache_home_node_file = {
146
+ node_id: home_node_id,
147
+ file_id: home_file_id
386
148
  }
387
- aoc_api.check_get_node_file(@home_node_file)
388
-
389
- return nil
149
+ return @cache_home_node_file
390
150
  end
391
151
 
392
152
  # get identifier or name from command line
@@ -396,11 +156,11 @@ module Aspera
396
156
  l_res_name = options.get_option(:name)
397
157
  raise 'Provide either option id or name, not both' unless l_res_id.nil? || l_res_name.nil?
398
158
  # 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?
159
+ l_res_id = aoc_api.lookup_entity_by_name(resource_class_path, l_res_name)['id'] unless l_res_name.nil?
400
160
  # if no name or id option, taken on command line (after command)
401
161
  if l_res_id.nil?
402
162
  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?('name')
163
+ 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
164
  end
405
165
  return l_res_id
406
166
  end
@@ -409,60 +169,14 @@ module Aspera
409
169
  return "#{resource_class_path}/#{get_resource_id_from_args(resource_class_path)}"
410
170
  end
411
171
 
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
172
  def normalize_metadata(pkg_data)
459
173
  case pkg_data['metadata']
460
- when Array,NilClass # no action
174
+ when Array, NilClass # no action
461
175
  when Hash
462
176
  api_meta = []
463
- pkg_data['metadata'].each do |k,v|
177
+ pkg_data['metadata'].each do |k, v|
464
178
  api_meta.push({
465
- #'input_type' => 'single-dropdown',
179
+ # 'input_type' => 'single-dropdown',
466
180
  'name' => k,
467
181
  'values' => v.is_a?(Array) ? v : [v]
468
182
  })
@@ -473,65 +187,18 @@ module Aspera
473
187
  return nil
474
188
  end
475
189
 
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
190
  def assert_public_link_types(expected)
524
- raise CliBadArgument,"public link type is #{@url_token_data['purpose']} but action requires one of #{expected.join(',')}" \
525
- unless expected.include?(@url_token_data['purpose'])
191
+ raise CliBadArgument, "public link type is #{aoc_api.url_token_data['purpose']} but action requires one of #{expected.join(',')}" \
192
+ unless expected.include?(aoc_api.url_token_data['purpose'])
526
193
  end
527
194
 
528
195
  # Call aoc_api.read with same parameters.
529
196
  # Use paging if necessary to get all results
530
197
  # @return {list: , total: }
531
- def read_with_paging(resource_class_path,base_query)
198
+ def read_with_paging(resource_class_path, base_query)
532
199
  raise 'Query must be Hash' unless base_query.is_a?(Hash)
533
200
  # 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.has_key?('per_page')
201
+ base_query['per_page'] = 1000 unless base_query.key?('per_page')
535
202
  max_items = base_query[MAX_ITEMS]
536
203
  base_query.delete(MAX_ITEMS)
537
204
  max_pages = base_query[MAX_PAGES]
@@ -544,7 +211,7 @@ module Aspera
544
211
  loop do
545
212
  query = base_query.clone
546
213
  query['page'] = current_page
547
- result = aoc_api.read(resource_class_path,query)
214
+ result = aoc_api.read(resource_class_path, query)
548
215
  total_count = result[:http]['X-Total-Count']
549
216
  page_count += 1
550
217
  current_page += 1
@@ -555,9 +222,67 @@ module Aspera
555
222
  break if !max_pages.nil? && page_count > max_pages
556
223
  break if !max_items.nil? && item_list.count > max_items
557
224
  end
558
- return {list: item_list,total: total_count}
225
+ return {list: item_list, total: total_count}
559
226
  end
560
227
 
228
+ NODE4_EXT_COMMANDS = %i[transfer].concat(Node::COMMANDS_GEN4).freeze
229
+ private_constant :NODE4_EXT_COMMANDS
230
+
231
+ # @param file_id [String] root file id for the operation (can be AK root, or other, e.g. package, or link)
232
+ # @param scope [String] node scope, or nil (admin)
233
+ def execute_nodegen4_command(command_repo, node_id, file_id: nil, scope: nil)
234
+ top_node_api = aoc_api.node_id_to_api(
235
+ node_id: node_id,
236
+ plugin: self,
237
+ scope: scope
238
+ )
239
+ 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?
240
+ node_plugin = Node.new(@agents.merge(
241
+ skip_basic_auth_options: true,
242
+ skip_node_options: true,
243
+ node_api: top_node_api))
244
+ case command_repo
245
+ when *Node::COMMANDS_GEN4
246
+ return node_plugin.execute_command_gen4(command_repo, file_id)
247
+ when :transfer
248
+ # client side is agent
249
+ # server side is protocol server
250
+ # in same workspace
251
+ # default is push
252
+ case options.get_option(:operation, is_type: :mandatory)
253
+ when :push
254
+ client_tr_oper = Fasp::TransferSpec::DIRECTION_SEND
255
+ client_folder = options.get_option(:from_folder, is_type: :mandatory)
256
+ server_folder = transfer.destination_folder(client_tr_oper)
257
+ when :pull
258
+ client_tr_oper = Fasp::TransferSpec::DIRECTION_RECEIVE
259
+ client_folder = transfer.destination_folder(client_tr_oper)
260
+ server_folder = options.get_option(:from_folder, is_type: :mandatory)
261
+ end
262
+ client_apfid = top_node_api.resolve_api_fid(file_id, client_folder)
263
+ server_apfid = top_node_api.resolve_api_fid(file_id, server_folder)
264
+ # force node as transfer agent
265
+ @agents[:transfer].agent_instance = Fasp::AgentNode.new({
266
+ url: client_apfid[:api].params[:base_url],
267
+ username: client_apfid[:api].app_info[:node_info]['access_key'],
268
+ password: client_apfid[:api].oauth_token,
269
+ root_id: client_apfid[:file_id]
270
+ })
271
+ # additional node to node TS info
272
+ add_ts = {
273
+ 'remote_access_key' => server_apfid[:api].app_info[:node_info]['access_key'],
274
+ 'destination_root_id' => server_apfid[:file_id],
275
+ 'source_root_id' => client_apfid[:file_id]
276
+ }
277
+ return Main.result_transfer(transfer.start(server_apfid[:api].transfer_spec_gen4(
278
+ server_apfid[:file_id],
279
+ client_tr_oper,
280
+ add_ts)))
281
+ else raise "INTERNAL ERROR: Missing case: #{command_repo}"
282
+ end # command_repo
283
+ # raise 'internal error:shall not reach here'
284
+ end # execute_nodegen4_command
285
+
561
286
  def execute_admin_action
562
287
  # upgrade scope to admin
563
288
  aoc_api.oauth.gparams[:scope] = AoC::SCOPE_FILES_ADMIN
@@ -568,7 +293,7 @@ module Aspera
568
293
  case command_auth_prov
569
294
  when :list
570
295
  providers = aoc_api.read('admin/auth_providers')[:data]
571
- return {type: :object_list,data: providers}
296
+ return {type: :object_list, data: providers}
572
297
  when :update
573
298
  raise 'not implemented'
574
299
  end
@@ -623,17 +348,17 @@ module Aspera
623
348
  }
624
349
  }
625
350
  "
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']}
351
+ result = bss_api.create('graphql', {'variables' => {'organization_id' => org['id']}, 'query' => graphql_query})[:data]['data']
352
+ return {type: :single_object, data: result['aoc']['bssSubscription']}
628
353
  when :ats
629
354
  ats_api = Rest.new(aoc_api.params.deep_merge({
630
355
  base_url: aoc_api.params[:base_url] + '/admin/ats/pub/v1',
631
356
  auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
632
357
  }))
633
- return Ats.new(@agents).execute_action_gen(ats_api)
358
+ return Ats.new(@agents.merge(skip_node_options: true)).execute_action_gen(ats_api)
634
359
  when :analytics
635
360
  analytics_api = Rest.new(aoc_api.params.deep_merge({
636
- base_url: aoc_api.params[:base_url].gsub('/api/v1','') + '/analytics/v2',
361
+ base_url: aoc_api.params[:base_url].gsub('/api/v1', '') + '/analytics/v2',
637
362
  auth: {scope: AoC::SCOPE_FILES_ADMIN_USER}
638
363
  }))
639
364
  command_analytics = options.get_next_command(%i[application_events transfers])
@@ -641,51 +366,53 @@ module Aspera
641
366
  when :application_events
642
367
  event_type = command_analytics.to_s
643
368
  events = analytics_api.read("organizations/#{aoc_api.user_info['organization_id']}/#{event_type}")[:data][event_type]
644
- return {type: :object_list,data: events}
369
+ return {type: :object_list, data: events}
645
370
  when :transfers
646
371
  event_type = command_analytics.to_s
647
372
  filter_resource = options.get_option(:name) || 'organizations'
648
373
  filter_id = options.get_option(:id) ||
649
- case filter_resource
650
- when 'organizations' then aoc_api.user_info['organization_id']
651
- when 'users' then aoc_api.user_info['id']
652
- when 'nodes' then aoc_api.user_info['id'] # TODO: consistent ? # rubocop:disable Lint/DuplicateBranch
653
- else raise 'organizations or users for option --name'
654
- end
374
+ case filter_resource
375
+ when 'organizations' then aoc_api.user_info['organization_id']
376
+ when 'users' then aoc_api.user_info['id']
377
+ when 'nodes' then aoc_api.user_info['id'] # TODO: consistent ? # rubocop:disable Lint/DuplicateBranch
378
+ else raise 'organizations or users for option --name'
379
+ end
655
380
  filter = options.get_option(:query) || {}
656
381
  raise 'query must be Hash' unless filter.is_a?(Hash)
657
382
  filter['limit'] ||= 100
658
- if options.get_option(:once_only,is_type: :mandatory)
383
+ if options.get_option(:once_only, is_type: :mandatory)
659
384
  saved_date = []
660
385
  startdate_persistency = PersistencyActionOnce.new(
661
386
  manager: @agents[:persistency],
662
387
  data: saved_date,
663
- ids: IdGenerator.from_list(['aoc_ana_date',options.get_option(:url,is_type: :mandatory),@workspace_info['name']].push(filter_resource,filter_id)))
388
+ ids: IdGenerator.from_list(['aoc_ana_date', options.get_option(:url, is_type: :mandatory), current_workspace_info['name']].push(
389
+ filter_resource,
390
+ filter_id)))
664
391
  start_datetime = saved_date.first
665
392
  stop_datetime = Time.now.utc.strftime('%FT%T.%LZ')
666
- #Log.log().error("start: #{start_datetime}")
667
- #Log.log().error("end: #{stop_datetime}")
393
+ # Log.log().error("start: #{start_datetime}")
394
+ # Log.log().error("end: #{stop_datetime}")
668
395
  saved_date[0] = stop_datetime
669
396
  filter['start_time'] = start_datetime unless start_datetime.nil?
670
397
  filter['stop_time'] = stop_datetime
671
398
  end
672
- events = analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}",option_url_query(filter))[:data][event_type]
399
+ events = analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}", option_url_query(filter))[:data][event_type]
673
400
  startdate_persistency&.save
674
401
  if !options.get_option(:notif_to).nil?
675
402
  events.each do |tr_event|
676
- config.send_email_template({ev: tr_event})
403
+ config.send_email_template(values: {ev: tr_event})
677
404
  end
678
405
  end
679
- return {type: :object_list,data: events}
406
+ return {type: :object_list, data: events}
680
407
  end
681
408
  when :resource
682
- resource_type = options.get_next_argument('resource',expected: KNOWN_AOC_RES)
409
+ resource_type = options.get_next_argument('resource', expected: KNOWN_AOC_RES)
683
410
  # get path on API, resource type is singular, but api is plural
684
411
  resource_class_path =
685
412
  case resource_type
686
413
  # special cases: singleton, in admin, with x
687
- when :self,:organization then resource_type
688
- when :client_registration_token,:client_access_key then "admin/#{resource_type}s"
414
+ when :self, :organization then resource_type
415
+ when :client_registration_token, :client_access_key then "admin/#{resource_type}s"
689
416
  when :application then 'admin/apps_new'
690
417
  when :dropbox then resource_type.to_s + 'es'
691
418
  when :kms_profile then "integrations/#{resource_type}s"
@@ -695,10 +422,9 @@ module Aspera
695
422
  singleton_object = %i[self organization].include?(resource_type)
696
423
  global_operations = %i[create list]
697
424
  supported_operations = %i[show modify]
698
- supported_operations.push(:delete,*global_operations) unless singleton_object
699
- supported_operations.push(:v4,:v3) if resource_type.eql?(:node)
425
+ supported_operations.push(:delete, *global_operations) unless singleton_object
426
+ supported_operations.push(:do) if resource_type.eql?(:node)
700
427
  supported_operations.push(:set_pub_key) if resource_type.eql?(:client)
701
- supported_operations.push(:shared_folder) if resource_type.eql?(:workspace)
702
428
  command = options.get_next_command(supported_operations)
703
429
  # require identifier for non global commands
704
430
  if !singleton_object && !global_operations.include?(command)
@@ -712,42 +438,43 @@ module Aspera
712
438
  id_result = 'token' if resource_class_path.eql?('admin/client_registration_tokens')
713
439
  # TODO: report inconsistency: creation url is !=, and does not return id.
714
440
  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 (Hash)')
716
- return do_bulk_operation(list_or_one,'created',id_result: id_result) do |params|
441
+ list_or_one = options.get_next_argument('creation data', type: Hash)
442
+ return do_bulk_operation(list_or_one, 'created', id_result: id_result) do |params|
717
443
  raise 'expecting Hash' unless params.is_a?(Hash)
718
- aoc_api.create(resource_class_path,params)[:data]
444
+ aoc_api.create(resource_class_path, params)[:data]
719
445
  end
720
446
  when :list
721
447
  default_fields = ['id']
722
448
  default_query = {}
723
449
  case resource_type
724
- when :application then default_query = {organization_apps: true};
725
- default_fields.push('app_type','app_name','available','direct_authorizations_allowed','workspace_authorizations_allowed')
726
- when :client,:client_access_key,:dropbox,:group,:package,:saml_configuration,:workspace then default_fields.push('name')
727
- when :client_registration_token then default_fields.push('value','data.client_subject_scopes','created_at')
450
+ when :application
451
+ default_query = {organization_apps: true}
452
+ default_fields.push('app_type', 'app_name', 'available', 'direct_authorizations_allowed', 'workspace_authorizations_allowed')
453
+ when :client, :client_access_key, :dropbox, :group, :package, :saml_configuration, :workspace then default_fields.push('name')
454
+ when :client_registration_token then default_fields.push('value', 'data.client_subject_scopes', 'created_at')
728
455
  when :contact then default_fields = %w[email name source_id source_type]
729
- when :node then default_fields.push('name','host','access_key')
456
+ when :node then default_fields.push('name', 'host', 'access_key')
730
457
  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')
458
+ when :short_link then default_fields.push('short_url', 'data.url_token_data.purpose')
459
+ when :user then default_fields.push('name', 'email')
733
460
  when :group_membership then default_fields.push(*%w[group_id member_type member_id])
734
461
  when :workspace_membership then default_fields.push(*%w[workspace_id member_type member_id])
735
462
  end
736
- items = read_with_paging(resource_class_path,option_url_query(default_query))
463
+ items = read_with_paging(resource_class_path, option_url_query(default_query))
737
464
  count_msg = "Items: #{items[:list].length}/#{items[:total]}"
738
465
  count_msg = count_msg.bg_red unless items[:list].length.eql?(items[:total].to_i)
739
466
  self.format.display_status(count_msg)
740
- return {type: :object_list,data: items[:list],fields: default_fields}
467
+ return {type: :object_list, data: items[:list], fields: default_fields}
741
468
  when :show
742
469
  object = aoc_api.read(resource_instance_path)[:data]
743
470
  fields = object.keys.reject{|k|k.eql?('certificate')}
744
471
  return { type: :single_object, data: object, fields: fields }
745
472
  when :modify
746
473
  changes = options.get_next_argument('modified parameters (hash)')
747
- aoc_api.update(resource_instance_path,changes)
474
+ aoc_api.update(resource_instance_path, changes)
748
475
  return Main.result_status('modified')
749
476
  when :delete
750
- return do_bulk_operation(res_id,'deleted') do |one_id|
477
+ return do_bulk_operation(res_id, 'deleted') do |one_id|
751
478
  aoc_api.delete("#{resource_class_path}/#{one_id}")
752
479
  {'id' => one_id}
753
480
  end
@@ -755,109 +482,15 @@ module Aspera
755
482
  # special : reads private and generate public
756
483
  the_private_key = options.get_next_argument('private_key')
757
484
  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})
485
+ aoc_api.update(resource_instance_path, {jwt_grant_enabled: true, public_key: the_public_key})
759
486
  return Main.result_success
760
- when :v3,:v4
761
- res_data = aoc_api.read(resource_instance_path)[:data]
762
- api_node = aoc_api.get_node_api(res_data)
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
487
+ when :do
488
+ command_repo = options.get_next_command(NODE4_EXT_COMMANDS)
489
+ return execute_nodegen4_command(command_repo, res_id)
857
490
  else raise 'unknown command'
858
491
  end
859
492
  when :usage_reports
860
- return {type: :object_list,data: aoc_api.read('usage_reports',{workspace_id: @workspace_info['id']})[:data]}
493
+ return {type: :object_list, data: aoc_api.read('usage_reports', {workspace_id: current_workspace_info['id']})[:data]}
861
494
  end
862
495
  end
863
496
 
@@ -869,13 +502,13 @@ module Aspera
869
502
  case command
870
503
  when :reminder
871
504
  # 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]
505
+ user_email = options.get_option(:username, is_type: :mandatory)
506
+ Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders', {email: user_email})[:data]
874
507
  return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
875
508
  when :servers
876
- return {type: :object_list,data: Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
509
+ return {type: :object_list, data: Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
877
510
  when :bearer_token
878
- return {type: :text,data: aoc_api.oauth_token}
511
+ return {type: :text, data: aoc_api.oauth_token}
879
512
  when :organization
880
513
  return { type: :single_object, data: aoc_api.read('organization')[:data] }
881
514
  when :tier_restrictions
@@ -887,99 +520,101 @@ module Aspera
887
520
  when :workspaces
888
521
  case options.get_next_command(%i[list current])
889
522
  when :list
890
- return {type: :object_list,data: aoc_api.read('workspaces')[:data],fields: %w[id name]}
523
+ return {type: :object_list, data: aoc_api.read('workspaces')[:data], fields: %w[id name]}
891
524
  when :current
892
- set_workspace_info
893
- return { type: :single_object, data: @workspace_info }
525
+ return { type: :single_object, data: current_workspace_info }
894
526
  end
895
527
  when :profile
896
528
  case options.get_next_command(%i[show modify])
897
529
  when :show
898
- return { type: :single_object, data: aoc_api.user_info }
530
+ return { type: :single_object, data: aoc_api.user_info(exception: true) }
899
531
  when :modify
900
- aoc_api.update("users/#{aoc_api.user_info['id']}",options.get_next_argument('modified parameters (hash)'))
532
+ aoc_api.update("users/#{aoc_api.user_info(exception: true)['id']}", options.get_next_argument('modified parameters (hash)'))
901
533
  return Main.result_status('modified')
902
534
  end
903
535
  end
904
536
  when :packages
905
- set_workspace_info if @url_token_data.nil?
906
- package_command = options.get_next_command([%i[shared_inboxes send recv list show delete],NODE4_CMD_PATH].flatten)
537
+ package_command = options.get_next_command(%i[shared_inboxes send recv list show delete].concat(Node::NODE4_READ_ACTIONS))
907
538
  case package_command
908
539
  when :shared_inboxes
909
540
  case options.get_next_command(%i[list show])
910
541
  when :list
911
542
  query = option_url_query(nil)
912
543
  if query.nil?
913
- query = {'embed[]' => 'dropbox','aggregate_permissions_by_dropbox' => true,'sort' => 'dropbox_name'}
914
- query['workspace_id']=@workspace_info['id'] unless @workspace_info['id'].eql?(:undefined)
544
+ query = {'embed[]' => 'dropbox', 'aggregate_permissions_by_dropbox' => true, 'sort' => 'dropbox_name'}
545
+ query['workspace_id'] = current_workspace_info['id'] unless current_workspace_info['id'].eql?(:undefined)
915
546
  end
916
- return {type: :object_list,data: aoc_api.read('dropbox_memberships',query)[:data],fields: ['dropbox_id','dropbox.name']}
547
+ return {type: :object_list, data: aoc_api.read('dropbox_memberships', query)[:data], fields: ['dropbox_id', 'dropbox.name']}
917
548
  when :show
918
- return {type: :single_object,data: aoc_api.read(get_resource_path_from_args('dropboxes'),query)[:data]}
549
+ return {type: :single_object, data: aoc_api.read(get_resource_path_from_args('dropboxes'), query)[:data]}
919
550
  end
920
551
  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)
552
+ package_data = options.get_option(:value, is_type: :mandatory)
553
+ raise CliBadArgument, 'value must be hash, refer to doc' unless package_data.is_a?(Hash)
923
554
 
924
- if !@url_token_data.nil?
555
+ if !aoc_api.url_token_data.nil?
925
556
  assert_public_link_types(%w[send_package_to_user send_package_to_dropbox])
926
- box_type = @url_token_data['purpose'].split('_').last
927
- package_data['recipients'] = [{'id' => @url_token_data['data']["#{box_type}_id"],'type' => box_type}]
557
+ box_type = aoc_api.url_token_data['purpose'].split('_').last
558
+ package_data['recipients'] = [{'id' => aoc_api.url_token_data['data']["#{box_type}_id"], 'type' => box_type}]
928
559
  # TODO: probably this line is not needed
929
- @workspace_info['id'] = @url_token_data['data']['workspace_id']
560
+ current_workspace_info['id'] = aoc_api.url_token_data['data']['workspace_id']
930
561
  end
931
562
 
932
- package_data['workspace_id'] = @workspace_info['id']
563
+ package_data['workspace_id'] = current_workspace_info['id']
933
564
 
934
565
  # list of files to include in package, optional
935
- #package_data['file_names']=self.transfer.ts_source_paths.map{|i|File.basename(i['source'])}
566
+ # package_data['file_names']=self.transfer.ts_source_paths.map{|i|File.basename(i['source'])}
936
567
 
937
568
  # lookup users
938
- resolve_package_recipients(package_data,'recipients')
939
- resolve_package_recipients(package_data,'bcc_recipients')
569
+ new_user_option = options.get_option(:new_user_option)
570
+ aoc_api.resolve_package_recipients(package_data, current_workspace_info['id'], 'recipients', new_user_option)
571
+ aoc_api.resolve_package_recipients(package_data, current_workspace_info['id'], 'bcc_recipients', new_user_option)
940
572
  normalize_metadata(package_data)
941
- validate_metadata(package_data) if options.get_option(:validate_metadata)
573
+ aoc_api.validate_metadata(package_data) if options.get_option(:validate_metadata)
942
574
 
943
575
  # 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]
576
+ package_info = aoc_api.create('packages', package_data)[:data]
948
577
 
949
578
  # tell AoC what to expect in package: 1 transfer (can also be done after transfer)
950
579
  # TODO: if multisession was used we should probably tell
951
580
  # 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')))
581
+ aoc_api.update("packages/#{package_info['id']}", {'sent' => true, 'transfers_expected' => 1})[:data]
582
+ package_node_api = aoc_api.node_id_to_api(
583
+ node_id: package_info['node_id'],
584
+ plugin: self,
585
+ package_info: package_info,
586
+ scope: AoC::SCOPE_NODE_USER
587
+ )
588
+ # raise error if necessary (but not return, package info is returned on success)
589
+ Main.result_transfer(transfer.start(package_node_api.transfer_spec_gen4(
590
+ package_info['contents_file_id'],
591
+ Fasp::TransferSpec::DIRECTION_SEND)))
958
592
  # return all info on package
959
593
  return { type: :single_object, data: package_info}
960
594
  when :recv
961
- if !@url_token_data.nil?
595
+ if !aoc_api.url_token_data.nil?
962
596
  assert_public_link_types(['view_received_package'])
963
- options.set_option(:id,@url_token_data['data']['package_id'])
597
+ options.set_option(:id, aoc_api.url_token_data['data']['package_id'])
964
598
  end
965
599
  # scalar here
966
600
  ids_to_download = instance_identifier
967
601
  skip_ids_data = []
968
602
  skip_ids_persistency = nil
969
- if options.get_option(:once_only,is_type: :mandatory)
603
+ if options.get_option(:once_only, is_type: :mandatory)
970
604
  skip_ids_persistency = PersistencyActionOnce.new(
971
605
  manager: @agents[:persistency],
972
606
  data: skip_ids_data,
973
- id: IdGenerator.from_list(['aoc_recv',options.get_option(:url,is_type: :mandatory),@workspace_info['id']].push(*@persist_ids)))
607
+ id: IdGenerator.from_list(['aoc_recv', options.get_option(:url, is_type: :mandatory),
608
+ current_workspace_info['id']].concat(aoc_api.additional_persistence_ids)))
974
609
  end
975
- if ids_to_download.eql?(VAL_ALL)
610
+ if VAL_ALL.eql?(ids_to_download)
976
611
  # get list of packages in inbox
977
- package_info = aoc_api.read('packages',{
612
+ package_info = aoc_api.read('packages', {
978
613
  'archived' => false,
979
614
  'exclude_dropbox_packages' => true,
980
615
  'has_content' => true,
981
616
  'received' => true,
982
- 'workspace_id' => @workspace_info['id']})[:data]
617
+ 'workspace_id' => current_workspace_info['id']})[:data]
983
618
  # remove from list the ones already downloaded
984
619
  ids_to_download = package_info.map{|e|e['id']}
985
620
  # array here
@@ -991,12 +626,18 @@ module Aspera
991
626
  self.format.display_status("found #{ids_to_download.length} package(s).")
992
627
  ids_to_download.each do |package_id|
993
628
  package_info = aoc_api.read("packages/#{package_id}")[:data]
994
- node_info = aoc_api.read("nodes/#{package_info['node_id']}")[:data]
995
629
  self.format.display_status("downloading package: #{package_info['name']}")
996
- add_ts = {'paths' => [{'source' => '.'}]}
997
- node_file = {node_info: node_info, file_id: package_info['contents_file_id']}
998
- statuses = transfer_start(AoC::PACKAGES_APP,Fasp::TransferSpec::DIRECTION_RECEIVE,node_file,AoC.package_tags(package_info,'download').merge(add_ts))
999
- result_transfer.push({'package' => package_id,Main::STATUS_FIELD => statuses})
630
+ package_node_api = aoc_api.node_id_to_api(
631
+ node_id: package_info['node_id'],
632
+ plugin: self,
633
+ package_info: package_info,
634
+ scope: AoC::SCOPE_NODE_USER
635
+ )
636
+ statuses = transfer.start(package_node_api.transfer_spec_gen4(
637
+ package_info['contents_file_id'],
638
+ Fasp::TransferSpec::DIRECTION_RECEIVE,
639
+ {'paths'=> [{'source' => '.'}]}))
640
+ result_transfer.push({'package' => package_id, Main::STATUS_FIELD => statuses})
1000
641
  # update skip list only if all transfer sessions completed
1001
642
  if TransferAgent.session_status(statuses).eql?(:success)
1002
643
  skip_ids_data.push(package_id)
@@ -1009,62 +650,61 @@ module Aspera
1009
650
  package_info = aoc_api.read("packages/#{package_id}")[:data]
1010
651
  return { type: :single_object, data: package_info }
1011
652
  when :list
1012
- display_fields=%w[id name bytes_transferred]
1013
- query = option_url_query({'archived' => false,'exclude_dropbox_packages' => true,'has_content' => true,'received' => true})
1014
- if query.has_key?('dropbox_name')
653
+ display_fields = %w[id name bytes_transferred]
654
+ query = option_url_query({'archived' => false, 'exclude_dropbox_packages' => true, 'has_content' => true, 'received' => true})
655
+ if query.key?('dropbox_name')
1015
656
  # convenience: specify name instead of id
1016
- raise 'not both dropbox_name and dropbox_id' if query.has_key?('dropbox_id')
1017
- query['dropbox_id'] = aoc_api.lookup_entity_by_name('dropboxes',query['dropbox_name'])['id']
657
+ raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
658
+ query['dropbox_id'] = aoc_api.lookup_entity_by_name('dropboxes', query['dropbox_name'])['id']
1018
659
  query.delete('dropbox_name')
1019
660
  end
1020
661
  raise 'option must be Hash' unless query.is_a?(Hash)
1021
- if @workspace_info['id'].eql?(:undefined)
662
+ if current_workspace_info['id'].eql?(:undefined)
1022
663
  display_fields.push('workspace_id')
1023
664
  else
1024
- query['workspace_id'] ||= @workspace_info['id']
665
+ query['workspace_id'] ||= current_workspace_info['id']
1025
666
  end
1026
- packages = aoc_api.read('packages',query)[:data]
1027
- return {type: :object_list,data: packages,fields: display_fields}
667
+ packages = aoc_api.read('packages', query)[:data]
668
+ return {type: :object_list, data: packages, fields: display_fields}
1028
669
  when :delete
1029
670
  list_or_one = instance_identifier
1030
- return do_bulk_operation(list_or_one,'deleted') do |id|
671
+ return do_bulk_operation(list_or_one, 'deleted') do |id|
1031
672
  raise 'expecting String identifier' unless id.is_a?(String) || id.is_a?(Integer)
1032
673
  aoc_api.delete("packages/#{id}")[:data]
1033
674
  end
1034
- when *NODE4_CMD_PATH
675
+ when *Node::NODE4_READ_ACTIONS
1035
676
  package_id = options.get_next_argument('package ID')
1036
- #path = options.get_next_argument('path', mandatory: false) || '/'
1037
677
  package_info = aoc_api.read("packages/#{package_id}")[:data]
1038
- package_node_file = {
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)
678
+ return execute_nodegen4_command(package_command, package_info['node_id'], file_id: package_info['file_id'], scope: AoC::SCOPE_NODE_USER)
1043
679
  end
1044
680
  when :files
1045
- # get workspace related information
1046
- set_workspace_info
1047
- set_home_node_file
1048
- command_repo = options.get_next_command([NODE4_COMMANDS,:short_link].flatten)
681
+ command_repo = options.get_next_command([:short_link].concat(NODE4_EXT_COMMANDS))
1049
682
  case command_repo
1050
- when *NODE4_COMMANDS then return execute_node_gen4_command(command_repo,@home_node_file)
683
+ when *NODE4_EXT_COMMANDS
684
+ return execute_nodegen4_command(command_repo, home_info[:node_id], file_id: home_info[:file_id], scope: AoC::SCOPE_NODE_USER)
1051
685
  when :short_link
686
+ # TODO: move to permissions ?
1052
687
  folder_dest = options.get_option(:to_folder)
1053
688
  value_option = options.get_option(:value)
1054
689
  case value_option
1055
690
  when 'public' then value_option = {'purpose' => 'token_auth_redirection'}
1056
691
  when 'private' then value_option = {'purpose' => 'shared_folder_auth_link'}
1057
- when NilClass,Hash then nil # keep value
692
+ when NilClass, Hash then nil # keep value
1058
693
  else raise 'value must be either: public, private, Hash or nil'
1059
694
  end
1060
695
  create_params = nil
1061
- node_file = nil
696
+ shared_apfid = nil
1062
697
  if !folder_dest.nil?
1063
- node_file = aoc_api.resolve_node_file(@home_node_file,folder_dest)
698
+ home_node_api = aoc_api.node_id_to_api(
699
+ node_id: home_info[:node_id],
700
+ plugin: self,
701
+ scope: AoC::SCOPE_NODE_USER
702
+ )
703
+ shared_apfid = home_node_api.resolve_api_fid(home_info[:file_id], folder_dest)
1064
704
  create_params = {
1065
- file_id: node_file[:file_id],
1066
- node_id: node_file[:node_info]['id'],
1067
- workspace_id: @workspace_info['id']
705
+ file_id: shared_apfid[:file_id],
706
+ node_id: shared_apfid[:api].app_info[:node_info]['id'],
707
+ workspace_id: current_workspace_info['id']
1068
708
  }
1069
709
  end
1070
710
  if !value_option.nil? && !create_params.nil?
@@ -1085,30 +725,29 @@ module Aspera
1085
725
  else
1086
726
  raise 'purpose must be one of: token_auth_redirection or shared_folder_auth_link'
1087
727
  end
1088
- options.set_option(:value,value_option)
728
+ options.set_option(:value, value_option)
1089
729
  end
1090
- result = entity_action(@api_aoc,'short_links',id_default: 'self')
1091
- if result[:data].is_a?(Hash) && result[:data].has_key?('created_at') && result[:data]['resource_type'].eql?('UrlToken')
1092
- node_api = aoc_api.get_node_api(node_file[:node_info])
730
+ result = entity_action(aoc_api, 'short_links', id_default: 'self')
731
+ if result[:data].is_a?(Hash) && result[:data].key?('created_at') && result[:data]['resource_type'].eql?('UrlToken')
1093
732
  # TODO: access level as arg
1094
- access_levels = Aspera::Node::ACCESS_LEVELS #['delete','list','mkdir','preview','read','rename','write']
733
+ access_levels = Aspera::Node::ACCESS_LEVELS # ['delete','list','mkdir','preview','read','rename','write']
1095
734
  perm_data = {
1096
- 'file_id' => node_file[:file_id],
735
+ 'file_id' => shared_apfid[:file_id],
1097
736
  'access_type' => 'user',
1098
737
  'access_id' => result[:data]['resource_id'],
1099
738
  'access_levels' => access_levels,
1100
739
  'tags' => {
1101
740
  'url_token' => true,
1102
- 'workspace_id' => @workspace_info['id'],
1103
- 'workspace_name' => @workspace_info['name'],
741
+ 'workspace_id' => current_workspace_info['id'],
742
+ 'workspace_name' => current_workspace_info['name'],
1104
743
  'folder_name' => 'my folder',
1105
744
  'created_by_name' => aoc_api.user_info['name'],
1106
745
  'created_by_email' => aoc_api.user_info['email'],
1107
- 'access_key' => node_file[:node_info]['access_key'],
1108
- 'node' => node_file[:node_info]['host']
746
+ 'access_key' => shared_apfid[:api].app_info[:node_info]['access_key'],
747
+ 'node' => shared_apfid[:api].app_info[:node_info]['host']
1109
748
  }
1110
749
  }
1111
- node_api.create("permissions?file_id=#{node_file[:file_id]}",perm_data)
750
+ shared_apfid[:api].create("permissions?file_id=#{shared_apfid[:file_id]}", perm_data)
1112
751
  # TODO: event ?
1113
752
  end
1114
753
  return result
@@ -1118,49 +757,49 @@ module Aspera
1118
757
  Log.log.warn('BETA: work under progress')
1119
758
  # automation api is not in the same place
1120
759
  automation_rest_params = aoc_api.params.clone
1121
- automation_rest_params[:base_url].gsub!('/api/','/automation/')
760
+ automation_rest_params[:base_url].gsub!('/api/', '/automation/')
1122
761
  automation_api = Rest.new(automation_rest_params)
1123
762
  command_automation = options.get_next_command(%i[workflows instances])
1124
763
  case command_automation
1125
764
  when :instances
1126
- return entity_action(@api_aoc,'workflow_instances')
765
+ return entity_action(aoc_api, 'workflow_instances')
1127
766
  when :workflows
1128
- wf_command = options.get_next_command([Plugin::ALL_OPS,:action,:launch].flatten)
767
+ wf_command = options.get_next_command(%i[action launch].concat(Plugin::ALL_OPS))
1129
768
  case wf_command
1130
769
  when *Plugin::ALL_OPS
1131
- return entity_command(wf_command,automation_api,'workflows',id_default: :id)
770
+ return entity_command(wf_command, automation_api, 'workflows', id_default: :id)
1132
771
  when :launch
1133
772
  wf_id = instance_identifier
1134
- data = automation_api.create("workflows/#{wf_id}/launch",{})[:data]
1135
- return {type: :single_object,data: data}
773
+ data = automation_api.create("workflows/#{wf_id}/launch", {})[:data]
774
+ return {type: :single_object, data: data}
1136
775
  when :action
1137
- #TODO: not complete
776
+ # TODO: not complete
1138
777
  wf_id = instance_identifier
1139
778
  wf_action_cmd = options.get_next_command(%i[list create show])
1140
- Log.log.warn("Not implemented: #{wf_action_cmd}")
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']]})
779
+ Log.log.warn{"Not implemented: #{wf_action_cmd}"}
780
+ step = automation_api.create('steps', {'workflow_id' => wf_id})[:data]
781
+ automation_api.update("workflows/#{wf_id}", {'step_order' => [step['id']]})
782
+ action = automation_api.create('actions', {'step_id' => step['id'], 'type' => 'manual'})[:data]
783
+ automation_api.update("steps/#{step['id']}", {'action_order' => [action['id']]})
1145
784
  wf = automation_api.read("workflows/#{wf_id}")[:data]
1146
- return {type: :single_object,data: wf}
785
+ return {type: :single_object, data: wf}
1147
786
  end
1148
787
  end
1149
788
  when :admin
1150
789
  return execute_admin_action
1151
790
  when :gateway
1152
- set_workspace_info
1153
791
  require 'aspera/faspex_gw'
1154
- FaspexGW.new(@api_aoc,@workspace_info['id']).start_server
792
+ return FaspexGW.new(aoc_api, current_workspace_info['id']).start_server
1155
793
  else
1156
794
  raise "internal error: #{command}"
1157
795
  end # action
1158
796
  raise 'internal error: command shall return'
1159
797
  end
1160
798
 
1161
- private :aoc_params,:set_workspace_info,:set_home_node_file,:do_bulk_operation,:resolve_package_recipients,:option_url_query,:assert_public_link_types,
799
+ private :aoc_params,
800
+ :home_info,
801
+ :assert_public_link_types,
1162
802
  :execute_admin_action
1163
- private_constant :VAL_ALL,:NODE4_COMMANDS, :ID_AK_ADMIN
1164
803
  end # AoC
1165
804
  end # Plugins
1166
805
  end # Cli