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