aspera-cli 4.9.0 → 4.11.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.
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