aspera-cli 4.0.0.pre3 → 4.2.1

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +695 -205
  3. data/bin/dascli +13 -0
  4. data/docs/README.erb.md +615 -157
  5. data/docs/test_env.conf +23 -5
  6. data/docs/transfer_spec.html +1 -1
  7. data/examples/aoc.rb +14 -3
  8. data/examples/faspex4.rb +78 -0
  9. data/lib/aspera/aoc.rb +87 -108
  10. data/lib/aspera/cli/formater.rb +2 -0
  11. data/lib/aspera/cli/main.rb +46 -34
  12. data/lib/aspera/cli/plugin.rb +9 -4
  13. data/lib/aspera/cli/plugins/alee.rb +1 -1
  14. data/lib/aspera/cli/plugins/aoc.rb +207 -182
  15. data/lib/aspera/cli/plugins/ats.rb +2 -2
  16. data/lib/aspera/cli/plugins/config.rb +173 -117
  17. data/lib/aspera/cli/plugins/console.rb +2 -2
  18. data/lib/aspera/cli/plugins/faspex.rb +51 -36
  19. data/lib/aspera/cli/plugins/faspex5.rb +82 -41
  20. data/lib/aspera/cli/plugins/node.rb +3 -3
  21. data/lib/aspera/cli/plugins/preview.rb +35 -25
  22. data/lib/aspera/cli/plugins/server.rb +23 -8
  23. data/lib/aspera/cli/transfer_agent.rb +7 -6
  24. data/lib/aspera/cli/version.rb +1 -1
  25. data/lib/aspera/cos_node.rb +33 -28
  26. data/lib/aspera/environment.rb +2 -2
  27. data/lib/aspera/fasp/connect.rb +28 -21
  28. data/lib/aspera/fasp/http_gw.rb +140 -28
  29. data/lib/aspera/fasp/installation.rb +101 -53
  30. data/lib/aspera/fasp/local.rb +88 -45
  31. data/lib/aspera/fasp/manager.rb +15 -0
  32. data/lib/aspera/fasp/node.rb +4 -4
  33. data/lib/aspera/fasp/parameters.rb +6 -18
  34. data/lib/aspera/fasp/resume_policy.rb +13 -12
  35. data/lib/aspera/log.rb +1 -1
  36. data/lib/aspera/node.rb +61 -1
  37. data/lib/aspera/oauth.rb +49 -46
  38. data/lib/aspera/persistency_folder.rb +9 -4
  39. data/lib/aspera/preview/file_types.rb +53 -21
  40. data/lib/aspera/preview/generator.rb +3 -3
  41. data/lib/aspera/rest.rb +29 -18
  42. data/lib/aspera/secrets.rb +20 -0
  43. data/lib/aspera/temp_file_manager.rb +19 -0
  44. data/lib/aspera/web_auth.rb +105 -0
  45. metadata +42 -22
@@ -151,6 +151,8 @@ module Aspera
151
151
  else
152
152
  if user_asked_fields_list_str.start_with?('+')
153
153
  result_default_fields(results,table_rows_hash_val).push(*user_asked_fields_list_str.gsub(/^\+/,'').split(','))
154
+ elsif user_asked_fields_list_str.start_with?('-')
155
+ result_default_fields(results,table_rows_hash_val).select{|i| ! user_asked_fields_list_str.gsub(/^\-/,'').split(',').include?(i)}
154
156
  else
155
157
  user_asked_fields_list_str.split(',')
156
158
  end
@@ -10,6 +10,7 @@ require 'aspera/persistency_folder'
10
10
  require 'aspera/log'
11
11
  require 'aspera/rest'
12
12
  require 'aspera/nagios'
13
+ require 'aspera/secrets'
13
14
 
14
15
  module Aspera
15
16
  module Cli
@@ -53,13 +54,22 @@ module Aspera
53
54
  @help_url='http://www.rubydoc.info/gems/'+GEM_NAME
54
55
  @gem_url='https://rubygems.org/gems/'+GEM_NAME
55
56
  # give command line arguments to option manager (no parsing)
56
- @plugin_env[:options]=@opt_mgr=Manager.new(self.program_name,argv,app_banner())
57
+ app_main_folder=ENV[conf_dir_env_var]
58
+ # if env var undefined or empty
59
+ if app_main_folder.nil? or app_main_folder.empty?
60
+ user_home_folder=Dir.home
61
+ raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{conf_dir_env_var}." unless Dir.exist?(user_home_folder)
62
+ app_main_folder=File.join(user_home_folder,Plugins::Config::ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME)
63
+ end
64
+ @plugin_env[:options]=@opt_mgr=Manager.new(PROGRAM_NAME,argv,app_banner())
57
65
  @plugin_env[:formater]=Formater.new(@plugin_env[:options])
58
- Rest.user_agent=self.program_name
66
+ Rest.user_agent=PROGRAM_NAME
59
67
  # must override help methods before parser called (in other constructors)
60
68
  init_global_options()
69
+ # secret manager
70
+ @plugin_env[:secret]=Aspera::Secrets.new
61
71
  # the Config plugin adds the @preset parser
62
- @plugin_env[:config]=Plugins::Config.new(@plugin_env,self.program_name,@help_url,Aspera::Cli::VERSION)
72
+ @plugin_env[:config]=Plugins::Config.new(@plugin_env,PROGRAM_NAME,@help_url,Aspera::Cli::VERSION,app_main_folder)
63
73
  # the TransferAgent plugin may use the @preset parser
64
74
  @plugin_env[:transfer]=TransferAgent.new(@plugin_env)
65
75
  Log.log.debug('created plugin env'.red)
@@ -73,21 +83,21 @@ module Aspera
73
83
  end
74
84
 
75
85
  def app_banner
76
- banner = "NAME\n\t#{self.program_name} -- a command line tool for Aspera Applications (v#{Aspera::Cli::VERSION})\n\n"
86
+ banner = "NAME\n\t#{PROGRAM_NAME} -- a command line tool for Aspera Applications (v#{Aspera::Cli::VERSION})\n\n"
77
87
  banner << "SYNOPSIS\n"
78
- banner << "\t#{self.program_name} COMMANDS [OPTIONS] [ARGS]\n"
79
- banner << "\n"
80
- banner << "DESCRIPTION\n"
88
+ banner << "\t#{PROGRAM_NAME} COMMANDS [OPTIONS] [ARGS]\n"
89
+ banner << "\nDESCRIPTION\n"
81
90
  banner << "\tUse Aspera application to perform operations on command line.\n"
82
91
  banner << "\tDocumentation and examples: #{@gem_url}\n"
83
- banner << "\texecute: #{self.program_name} conf doc\n"
92
+ banner << "\texecute: #{PROGRAM_NAME} conf doc\n"
84
93
  banner << "\tor visit: #{@help_url}\n"
85
- banner << "\n"
86
- banner << "COMMANDS\n"
87
- banner << "\tTo list first level commands, execute: #{self.program_name}\n"
94
+ banner << "\nENVIRONMENT VARIABLES\n"
95
+ banner << "\t#{conf_dir_env_var} config folder, default: $HOME/#{Plugins::Config::ASPERA_HOME_FOLDER_NAME}/#{PROGRAM_NAME}\n"
96
+ banner << "\t#any option can be set as an environment variable, refer to the manual\n"
97
+ banner << "\nCOMMANDS\n"
98
+ banner << "\tTo list first level commands, execute: #{PROGRAM_NAME}\n"
88
99
  banner << "\tNote that commands can be written shortened (provided it is unique).\n"
89
- banner << "\n"
90
- banner << "OPTIONS\n"
100
+ banner << "\nOPTIONS\n"
91
101
  banner << "\tOptions begin with a '-' (minus), and value is provided on command line.\n"
92
102
  banner << "\tSpecial values are supported beginning with special prefix, like: #{ExtendedValue.instance.modifiers.map{|m|"@#{m}:"}.join(' ')}.\n"
93
103
  banner << "\tDates format is 'DD-MM-YY HH:MM:SS', or 'now' or '-<num>h'\n\n"
@@ -167,7 +177,7 @@ module Aspera
167
177
  # override main option parser with a brand new, to avoid having global options
168
178
  plugin_env=@plugin_env.clone
169
179
  plugin_env[:man_only]=true
170
- plugin_env[:options]=Manager.new(self.program_name,[],'')
180
+ plugin_env[:options]=Manager.new(PROGRAM_NAME,[],'')
171
181
  get_plugin_instance_with_options(plugin_name_sym,plugin_env)
172
182
  # display generated help for plugin options
173
183
  @plugin_env[:formater].display_message(:error,plugin_env[:options].parser.to_s)
@@ -178,10 +188,14 @@ module Aspera
178
188
 
179
189
  protected
180
190
 
191
+ def conf_dir_env_var
192
+ return "#{PROGRAM_NAME}_home".upcase
193
+ end
194
+
181
195
  # early debug for parser
182
196
  # Note: does not accept shortcuts
183
197
  def early_debug_setup(argv)
184
- Log.instance.program_name=self.program_name
198
+ Log.instance.program_name=PROGRAM_NAME
185
199
  argv.each do |arg|
186
200
  case arg
187
201
  when '--'
@@ -205,10 +219,6 @@ module Aspera
205
219
  return Main.result_nothing
206
220
  end
207
221
 
208
- def options;@opt_mgr;end
209
-
210
- def program_name;PROGRAM_NAME;end
211
-
212
222
  # this is the main function called by initial script just after constructor
213
223
  def process_command_line
214
224
  Log.log.debug('process_command_line')
@@ -222,16 +232,7 @@ module Aspera
222
232
  # load global default options and process
223
233
  @plugin_env[:config].add_plugin_default_preset(Plugins::Config::CONF_GLOBAL_SYM)
224
234
  @opt_mgr.parse_options!
225
- # dual execution locking
226
- lock_port=@opt_mgr.get_option(:lock_port,:optional)
227
- if !lock_port.nil?
228
- begin
229
- # no need to close later, will be freed on process exit. must save in member else it is garbage collected
230
- @tcp_server=TCPServer.new('127.0.0.1',lock_port.to_i)
231
- rescue => e
232
- raise CliError,"Another instance is already running (lock port=#{lock_port})."
233
- end
234
- end
235
+ @plugin_env[:config].periodic_check_newer_gem_version
235
236
  if @option_show_config and @opt_mgr.command_or_arg_empty?
236
237
  command_sym=Plugins::Config::CONF_PLUGIN_SYM
237
238
  else
@@ -255,6 +256,17 @@ module Aspera
255
256
  @plugin_env[:formater].display_results({:type=>:single_object,:data=>@opt_mgr.declared_options(false)})
256
257
  Process.exit(0)
257
258
  end
259
+ # locking for single execution (only after "per plugin" option, in case lock port is there)
260
+ lock_port=@opt_mgr.get_option(:lock_port,:optional)
261
+ if !lock_port.nil?
262
+ begin
263
+ # no need to close later, will be freed on process exit. must save in member else it is garbage collected
264
+ Log.log.debug("Opening lock port #{lock_port.to_i}")
265
+ @tcp_server=TCPServer.new('127.0.0.1',lock_port.to_i)
266
+ rescue => e
267
+ raise CliError,"Another instance is already running (#{e.message})."
268
+ end
269
+ end
258
270
  # execute and display
259
271
  @plugin_env[:formater].display_results(command_plugin.execute_action)
260
272
  # finish
@@ -262,11 +274,11 @@ module Aspera
262
274
  rescue CliBadArgument => e; exception_info=[e,'Argument',:usage]
263
275
  rescue CliNoSuchId => e; exception_info=[e,'Identifier']
264
276
  rescue CliError => e; exception_info=[e,'Tool',:usage]
265
- rescue Fasp::Error => e; exception_info=[e,"FASP(ascp]"]
266
- rescue Aspera::RestCallError => e; exception_info=[e,"Rest"]
267
- rescue SocketError => e; exception_info=[e,"Network"]
268
- rescue StandardError => e; exception_info=[e,"Other",:debug]
269
- rescue Interrupt => e; exception_info=[e,"Interruption",:debug]
277
+ rescue Fasp::Error => e; exception_info=[e,'FASP(ascp)']
278
+ rescue Aspera::RestCallError => e; exception_info=[e,'Rest']
279
+ rescue SocketError => e; exception_info=[e,'Network']
280
+ rescue StandardError => e; exception_info=[e,'Other',:debug]
281
+ rescue Interrupt => e; exception_info=[e,'Interruption',:debug]
270
282
  end
271
283
  # cleanup file list files
272
284
  TempFileManager.instance.cleanup
@@ -67,7 +67,10 @@ module Aspera
67
67
  when :delete
68
68
  rest_api.delete(one_res_path)
69
69
  return Main.result_status("deleted")
70
+ else
71
+ raise "unknown action: #{command}"
70
72
  end
73
+ raise "internal error should not reach here"
71
74
  end
72
75
 
73
76
  # implement generic rest operations on given resource path
@@ -77,13 +80,15 @@ module Aspera
77
80
  return entity_command(command,rest_api,res_class_path,display_fields,id_symb,id_default,subkey)
78
81
  end
79
82
 
80
- def options;@agents[:options];end
83
+ def options; return @agents[:options];end
81
84
 
82
- def transfer;@agents[:transfer];end
85
+ def transfer; return @agents[:transfer];end
83
86
 
84
- def config;return @agents[:config];end
87
+ def config; return @agents[:config];end
85
88
 
86
- def format;return @agents[:formater];end
89
+ def format; return @agents[:formater];end
90
+
91
+ def persistency; return @agents[:persistency];end
87
92
 
88
93
  end # Plugin
89
94
  end # Cli
@@ -12,7 +12,7 @@ module Aspera
12
12
  command=self.options.get_next_command(ACTIONS)
13
13
  case command
14
14
  when :entitlement
15
- entitlement_id = self.options.get_option(:username,:mandatory),
15
+ entitlement_id = self.options.get_option(:username,:mandatory)
16
16
  customer_id = self.options.get_option(:password,:mandatory)
17
17
  api_metering=AoC.metering_api(entitlement_id,customer_id)
18
18
  return {:type=>:single_object, :data=>api_metering.read('entitlement')[:data]}
@@ -3,6 +3,7 @@ require 'aspera/cli/plugins/ats'
3
3
  require 'aspera/cli/basic_auth_plugin'
4
4
  require 'aspera/cli/transfer_agent'
5
5
  require 'aspera/aoc'
6
+ require 'aspera/node'
6
7
  require 'aspera/persistency_action_once'
7
8
  require 'securerandom'
8
9
  require 'resolv'
@@ -12,9 +13,8 @@ module Aspera
12
13
  module Cli
13
14
  module Plugins
14
15
  class Aoc < BasicAuthPlugin
16
+ # special value for package id
15
17
  VAL_ALL='ALL'
16
- private_constant :VAL_ALL
17
- attr_reader :api_aoc
18
18
  def initialize(env)
19
19
  super(env)
20
20
  @default_workspace_id=nil
@@ -25,23 +25,23 @@ module Aspera
25
25
  @api_aoc=nil
26
26
  @url_token_data=nil
27
27
  @user_info=nil
28
- @ats=Ats.new(@agents)
29
- self.options.add_opt_list(:auth,Oauth.auth_types,"type of Oauth authentication")
30
- self.options.add_opt_list(:operation,[:push,:pull],"client operation for transfers")
31
- self.options.add_opt_simple(:client_id,"API client identifier in application")
32
- self.options.add_opt_simple(:client_secret,"API client passcode")
33
- self.options.add_opt_simple(:redirect_uri,"API client redirect URI")
34
- self.options.add_opt_simple(:private_key,"RSA private key PEM value for JWT (prefix file path with @val:@file:)")
35
- self.options.add_opt_simple(:workspace,"name of workspace")
36
- self.options.add_opt_simple(:eid,"identifier") # used ?
37
- self.options.add_opt_simple(:name,"resource name")
38
- self.options.add_opt_simple(:link,"public link to shared resource")
39
- self.options.add_opt_simple(:new_user_option,"new user creation option")
40
- self.options.add_opt_simple(:from_folder,"share to share source folder")
41
- self.options.add_opt_simple(:scope,"scope for AoC API calls")
42
- self.options.add_opt_simple(:notify,"notify users that file was received")
43
- self.options.add_opt_boolean(:bulk,"bulk operation")
44
- self.options.add_opt_boolean(:default_ports,"use standard FASP ports or get from node api")
28
+ @api_aoc=nil
29
+ self.options.add_opt_list(:auth,Oauth.auth_types,'OAuth type of authentication')
30
+ self.options.add_opt_list(:operation,[:push,:pull],'client operation for transfers')
31
+ self.options.add_opt_simple(:client_id,'OAuth API client identifier in application')
32
+ self.options.add_opt_simple(:client_secret,'OAuth API client passcode')
33
+ self.options.add_opt_simple(:redirect_uri,'OAuth API client redirect URI')
34
+ self.options.add_opt_simple(:private_key,'OAuth JWT RSA private key PEM value (prefix file path with @val:@file:)')
35
+ self.options.add_opt_simple(:workspace,'name of workspace')
36
+ self.options.add_opt_simple(:name,'resource name')
37
+ self.options.add_opt_simple(:path,'file or folder path')
38
+ self.options.add_opt_simple(:link,'public link to shared resource')
39
+ self.options.add_opt_simple(:new_user_option,'new user creation option')
40
+ self.options.add_opt_simple(:from_folder,'share to share source folder')
41
+ self.options.add_opt_simple(:scope,'OAuth scope for AoC API calls')
42
+ self.options.add_opt_simple(:notify,'notify users that file was received')
43
+ self.options.add_opt_boolean(:bulk,'bulk operation')
44
+ self.options.add_opt_boolean(:default_ports,'use standard FASP ports or get from node api')
45
45
  self.options.set_option(:bulk,:no)
46
46
  self.options.set_option(:default_ports,:yes)
47
47
  self.options.set_option(:new_user_option,{'package_contact'=>true})
@@ -52,20 +52,19 @@ module Aspera
52
52
  self.options.parse_options!
53
53
  AoC.set_use_default_ports(self.options.get_option(:default_ports))
54
54
  return if env[:man_only]
55
- update_aoc_api
56
55
  end
57
56
 
58
- # call this to populate single AK secret in AoC API object, from options
59
- # make sure secret is available
60
- def find_ak_secret(ak,mandatory=true)
61
- # secret hash is already provisioned
62
- # optionally override with specific secret
63
- @api_aoc.add_secrets({ak=>self.config.get_secret(ak,mandatory)})
64
- # check that secret was provided as single value or dictionary
65
- raise CliBadArgument,"Please provide option secret or entry in option secrets for: #{ak}" unless @api_aoc.has_secret(ak) or !mandatory
57
+ def get_api
58
+ if @api_aoc.nil?
59
+ @api_aoc=AoC.new(aoc_params(AoC::API_V1))
60
+ # add keychain for access key secrets
61
+ @api_aoc.key_chain=@agents[:secret]
62
+ end
63
+ return @api_aoc
66
64
  end
67
65
 
68
- def user_info
66
+ # cached user information
67
+ def c_user_info
69
68
  if @user_info.nil?
70
69
  # get our user's default information
71
70
  # self?embed[]=default_workspace&embed[]=organization
@@ -80,16 +79,11 @@ module Aspera
80
79
  # starts transfer using transfer agent
81
80
  def transfer_start(app,direction,node_file,ts_add)
82
81
  ts_add.deep_merge!(AoC.analytics_ts(app,direction,@workspace_id,@workspace_name))
83
- ts_add.deep_merge!(AoC.console_ts(app,user_info['name'],user_info['email']))
82
+ ts_add.deep_merge!(AoC.console_ts(app,c_user_info['name'],c_user_info['email']))
84
83
  return self.transfer.start(*@api_aoc.tr_spec(app,direction,node_file,ts_add))
85
84
  end
86
85
 
87
- NODE4_COMMANDS=[ :browse, :find, :mkdir, :rename, :delete, :upload, :download, :transfer, :http_node_download, :v3, :file, :bearer_token_node, :permissions ]
88
-
89
- def node_gen4_execute_action(top_node_file)
90
- command_repo=self.options.get_next_command(NODE4_COMMANDS)
91
- return execute_node_gen4_command(command_repo,top_node_file)
92
- end
86
+ NODE4_COMMANDS=[ :browse, :find, :mkdir, :rename, :delete, :upload, :download, :transfer, :http_node_download, :v3, :file, :bearer_token_node ]
93
87
 
94
88
  def execute_node_gen4_command(command_repo,top_node_file)
95
89
  case command_repo
@@ -113,14 +107,8 @@ module Aspera
113
107
  return {:type=>:object_list,:data=>items,:fields=>['name','type','recursive_size','size','modified_time','access_level']}
114
108
  when :find
115
109
  thepath=self.options.get_next_argument('path')
116
- exec_prefix='exec:'
117
- expression=self.options.get_option(:value,:optional)||"#{exec_prefix}true"
118
110
  node_file=@api_aoc.resolve_node_file(top_node_file,thepath)
119
- if expression.start_with?(exec_prefix)
120
- test_block=eval "lambda{|f|#{expression[exec_prefix.length..-1]}}"
121
- else
122
- test_block=lambda{|f|f['name'].match(/#{expression}/)}
123
- end
111
+ test_block=Aspera::Node.file_matcher(self.options.get_option(:value,:optional))
124
112
  return {:type=>:object_list,:data=>@api_aoc.find_files(node_file,test_block),:fields=>['path']}
125
113
  when :mkdir
126
114
  thepath=self.options.get_next_argument('path')
@@ -139,12 +127,12 @@ module Aspera
139
127
  return Main.result_status("renamed #{thepath} to #{newname}")
140
128
  when :delete
141
129
  thepath=self.options.get_next_argument('path')
142
- return do_bulk_operation(thepath,'deleted','path') do |thepath|
143
- raise "expecting String (path), got #{thepath.class.name} (#{thepath})" unless thepath.is_a?(String)
144
- node_file = @api_aoc.resolve_node_file(top_node_file,thepath)
130
+ return do_bulk_operation(thepath,'deleted','path') do |l_path|
131
+ raise "expecting String (path), got #{l_path.class.name} (#{l_path})" unless l_path.is_a?(String)
132
+ node_file = @api_aoc.resolve_node_file(top_node_file,l_path)
145
133
  node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
146
134
  result=node_api.delete("files/#{node_file[:file_id]}")[:data]
147
- {'path'=>thepath}
135
+ {'path'=>l_path}
148
136
  end
149
137
  when :transfer
150
138
  # client side is agent
@@ -213,69 +201,79 @@ module Aspera
213
201
  node_api=@api_aoc.get_node_api(top_node_file[:node_info],AoC::SCOPE_NODE_USER)
214
202
  return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: node_api)).execute_action(command_legacy)
215
203
  when :file
216
- fileid=self.options.get_next_argument('file id')
217
- node_file = @api_aoc.resolve_node_file(top_node_file)
218
- node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
219
- items=node_api.read("files/#{fileid}")[:data]
220
- return {:type=>:single_object,:data=>items}
221
- when :permissions
222
- fileid=self.options.get_next_argument('file id')
223
- node_file = @api_aoc.resolve_node_file(top_node_file)
204
+ file_path=self.options.get_option(:path,:optional)
205
+ node_file = if !file_path.nil?
206
+ @api_aoc.resolve_node_file(top_node_file,file_path) # TODO: allow follow link ?
207
+ else
208
+ {node_info: top_node_file[:node_info],file_id: self.options.get_option(:id,:mandatory)}
209
+ end
224
210
  node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
225
- command_perms=self.options.get_next_command([:show,:create])
226
- case command_perms
211
+ command_node_file=self.options.get_next_command([:show,:permission,:modify])
212
+ case command_node_file
227
213
  when :show
228
- items=node_api.read('permissions',{'include'=>['[]','access_level','permission_count'],'file_id'=>fileid,'inherited'=>false})[:data]
229
- return {:type=>:object_list,:data=>items}
230
- when :create
231
- #value=self.options.get_next_argument('creation value')
232
- set_workspace_info
233
- access_id="ASPERA_ACCESS_KEY_ADMIN_WS_#{@workspace_id}"
234
- node_file[:node_info]
235
- params={
236
- "file_id"=>fileid,
237
- "access_type"=>"user",
238
- "access_id"=>access_id,
239
- "access_levels"=>["list","read","write","delete","mkdir","rename","preview"],
240
- "tags"=>{
241
- "aspera"=>{
242
- "files"=>{
243
- "workspace"=>{
244
- "id"=>@workspace_id,
245
- "workspace_name"=>@workspace_name,
246
- "user_name"=>user_info['name'],
247
- "shared_by_user_id"=>user_info['id'],
248
- "shared_by_name"=>user_info['name'],
249
- "shared_by_email"=>user_info['email'],
250
- "shared_with_name"=>access_id,
251
- "access_key"=>node_file[:node_info]['access_key'],
252
- "node"=>node_file[:node_info]['name']}}}}}
253
- item=node_api.create('permissions',params)[:data]
254
- return {:type=>:single_object,:data=>item}
255
- else raise "error"
214
+ items=node_api.read("files/#{node_file[:file_id]}")[:data]
215
+ return {:type=>:single_object,:data=>items}
216
+ when :modify
217
+ update_param=self.options.get_next_argument("update data (Hash)")
218
+ res=node_api.update("files/#{node_file[:file_id]}",update_param)[:data]
219
+ return {:type=>:single_object,:data=>res}
220
+ when :permission
221
+ command_perm=self.options.get_next_command([:list,:create])
222
+ case command_perm
223
+ when :list
224
+ # generic options : TODO: as arg ?
225
+ list_options||={'include'=>['[]','access_level','permission_count']}
226
+ # special value: ALL will show all permissions
227
+ if !VAL_ALL.eql?(node_file[:file_id])
228
+ # add which one to get
229
+ list_options['file_id']=node_file[:file_id]
230
+ list_options['inherited']||=false
231
+ end
232
+ #option_url_query
233
+ items=node_api.read('permissions',list_options)[:data]
234
+ return {:type=>:object_list,:data=>items}
235
+ when :create
236
+ #create_param=self.options.get_next_argument("creation data (Hash)")
237
+ set_workspace_info
238
+ access_id="ASPERA_ACCESS_KEY_ADMIN_WS_#{@workspace_id}"
239
+ node_file[:node_info]
240
+ params={
241
+ 'file_id' =>node_file[:file_id], # mandatory
242
+ 'access_type' =>'user', # mandatory: user or group
243
+ 'access_id' =>access_id, # id of user or group
244
+ 'access_levels'=>Aspera::Node::ACCESS_LEVELS,
245
+ 'tags' =>{'aspera'=>{'files'=>{'workspace'=>{
246
+ 'id' =>@workspace_id,
247
+ 'workspace_name' =>@workspace_name,
248
+ 'user_name' =>c_user_info['name'],
249
+ 'shared_by_user_id'=>c_user_info['id'],
250
+ 'shared_by_name' =>c_user_info['name'],
251
+ 'shared_by_email' =>c_user_info['email'],
252
+ 'shared_with_name' =>access_id,
253
+ 'access_key' =>node_file[:node_info]['access_key'],
254
+ 'node' =>node_file[:node_info]['name']}}}}}
255
+ item=node_api.create('permissions',params)[:data]
256
+ return {:type=>:single_object,:data=>item}
257
+ else raise "internal error:shall not reach here (#{command_perm})"
258
+ end
259
+ raise "internal error:shall not reach here"
260
+ else raise "internal error:shall not reach here (#{command_node_file})"
256
261
  end
262
+ raise "internal error:shall not reach here"
263
+ when :permissions
264
+
257
265
  end # command_repo
258
- throw "ERR"
266
+ raise "ERR"
259
267
  end # execute_node_gen4_command
260
268
 
261
269
  # build constructor option list for AoC based on options of CLI
262
270
  def aoc_params(subpath)
263
271
  # copy command line options to args
264
- opt=[:link,:url,:auth,:client_id,:client_secret,:scope,:redirect_uri,:private_key,:username].inject({}){|m,i|m[i]=self.options.get_option(i,:optional);m}
272
+ 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}
265
273
  opt[:subpath]=subpath
266
274
  return opt
267
275
  end
268
276
 
269
- # Create a new AoC API REST object and set @api_aoc.
270
- # Parameters based on command line options
271
- # @return nil
272
- def update_aoc_api
273
- @api_aoc=AoC.new(aoc_params('api/v1'))
274
- # add access key secrets
275
- @api_aoc.add_secrets(self.config.get_secrets)
276
- return nil
277
- end
278
-
279
277
  # initialize apis and authentication
280
278
  # set:
281
279
  # @default_workspace_id
@@ -290,8 +288,8 @@ module Aspera
290
288
  @default_workspace_id=@url_token_data['data']['workspace_id']
291
289
  @persist_ids=[] # TODO : @url_token_data['id'] ?
292
290
  else
293
- @default_workspace_id=user_info['default_workspace_id']
294
- @persist_ids=[user_info['id']]
291
+ @default_workspace_id=c_user_info['default_workspace_id']
292
+ @persist_ids=[c_user_info['id']]
295
293
  end
296
294
 
297
295
  ws_name=self.options.get_option(:workspace,:optional)
@@ -401,7 +399,8 @@ module Aspera
401
399
  package_creation[recipient_list_field]=resolved_list
402
400
  end
403
401
 
404
- def url_query(default)
402
+ # private
403
+ def option_url_query(default)
405
404
  query=self.options.get_option(:query,:optional)||default
406
405
  Log.log.debug("Query=#{query}".bg_red)
407
406
  begin
@@ -420,8 +419,7 @@ module Aspera
420
419
  end
421
420
 
422
421
  def execute_admin_action
423
- self.options.set_option(:scope,AoC::SCOPE_FILES_ADMIN)
424
- update_aoc_api
422
+ @api_aoc.oauth.params[:scope]=AoC::SCOPE_FILES_ADMIN
425
423
  command_admin=self.options.get_next_command([ :ats, :resource, :usage_reports, :analytics, :subscription, :auth_providers ])
426
424
  case command_admin
427
425
  when :auth_providers
@@ -490,20 +488,7 @@ module Aspera
490
488
  :base_url => @api_aoc.params[:base_url]+'/admin/ats/pub/v1',
491
489
  :auth => {:scope => AoC::SCOPE_FILES_ADMIN_USER}
492
490
  }))
493
- return @ats.execute_action_gen(ats_api)
494
- # when :search_nodes
495
- # query=self.options.get_option(:query,:optional) || '*'
496
- # nodes=@api_aoc.read("search_nodes",{'q'=>query})[:data]
497
- # # simplify output
498
- # nodes=nodes.map do |i|
499
- # item=i['_source']
500
- # item['score']=i['_score']
501
- # nodedata=item['access_key_recursive_counts'].first
502
- # item.delete('access_key_recursive_counts')
503
- # item['node']=nodedata
504
- # item
505
- # end
506
- # return {:type=>:object_list,:data=>nodes,:fields=>['host_name','node_status.cluster_id','node_status.node_id']}
491
+ return Ats.new(@agents).execute_action_gen(ats_api)
507
492
  when :analytics
508
493
  analytics_api = Rest.new(@api_aoc.params.deep_merge({
509
494
  :base_url => @api_aoc.params[:base_url].gsub('/api/v1','')+'/analytics/v2',
@@ -513,19 +498,20 @@ module Aspera
513
498
  case command_analytics
514
499
  when :application_events
515
500
  event_type=command_analytics.to_s
516
- events=analytics_api.read("organizations/#{user_info['organization_id']}/#{event_type}")[:data][event_type]
501
+ events=analytics_api.read("organizations/#{c_user_info['organization_id']}/#{event_type}")[:data][event_type]
517
502
  return {:type=>:object_list,:data=>events}
518
503
  when :transfers
519
504
  event_type=command_analytics.to_s
520
505
  filter_resource=self.options.get_option(:name,:optional) || 'organizations'
521
506
  filter_id=self.options.get_option(:id,:optional) || case filter_resource
522
- when 'organizations'; user_info['organization_id']
523
- when 'users'; user_info['id']
524
- when 'nodes'; user_info['id']
507
+ when 'organizations'; c_user_info['organization_id']
508
+ when 'users'; c_user_info['id']
509
+ when 'nodes'; c_user_info['id']
525
510
  else raise "organizations or users for option --name"
526
511
  end
527
512
  #
528
513
  filter=self.options.get_option(:query,:optional) || {}
514
+ raise "query must be Hash" unless filter.is_a?(Hash)
529
515
  filter['limit']||=100
530
516
  if self.options.get_option(:once_only,:mandatory)
531
517
  saved_date=[]
@@ -542,7 +528,7 @@ module Aspera
542
528
  filter['stop_time'] = stop_datetime
543
529
  end
544
530
  notification=self.options.get_option(:notify,:optional)
545
- events=analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}",url_query(filter))[:data][event_type]
531
+ events=analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}",option_url_query(filter))[:data][event_type]
546
532
  startdate_persistency.save unless startdate_persistency.nil?
547
533
  if !notification.nil?
548
534
  require 'erb'
@@ -558,17 +544,31 @@ module Aspera
558
544
  return {:type=>:object_list,:data=>events}
559
545
  end
560
546
  when :resource
561
- 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,'admin/apps_new'.to_sym,'admin/client_registration_token'.to_sym,'integrations/kms_profile'.to_sym])
562
- resource_class_path=resource_type.to_s+case resource_type;when :dropbox;'es';when :self,:organization,'admin/apps_new'.to_sym;'';else; 's';end
547
+ 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,:apps_new,:client_registration_token,:client_access_key,:kms_profile])
548
+ # get path on API
549
+ resource_class_path=case resource_type
550
+ when :self,:organization
551
+ "#{resource_type}"
552
+ when :apps_new
553
+ "admin/#{resource_type}"
554
+ when :dropbox
555
+ resource_type.to_s+'es'
556
+ when :client_registration_token,:client_access_key
557
+ "admin/#{resource_type}s"
558
+ when :kms_profile
559
+ "integrations/#{resource_type}s"
560
+ else
561
+ resource_type.to_s+'s'
562
+ end
563
+ # build list of supported operations
563
564
  singleton_object=[:self,:organization].include?(resource_type)
564
565
  global_operations=[:create,:list]
565
566
  supported_operations=[:show,:modify]
566
567
  supported_operations.push(:delete,*global_operations) unless singleton_object
567
568
  supported_operations.push(:v4,:v3) if resource_type.eql?(:node)
568
569
  supported_operations.push(:set_pub_key) if resource_type.eql?(:client)
569
- supported_operations.push(:shared_folders) if [:node,:workspace].include?(resource_type)
570
+ supported_operations.push(:shared_folders,:shared_create) if [:node,:workspace].include?(resource_type)
570
571
  command=self.options.get_next_command(supported_operations)
571
-
572
572
  # require identifier for non global commands
573
573
  if !singleton_object and !global_operations.include?(command)
574
574
  res_id=self.options.get_option(:id)
@@ -607,11 +607,13 @@ module Aspera
607
607
  when :node; default_fields.push('host','access_key')
608
608
  when :operation; default_fields=nil
609
609
  when :contact; default_fields=["email","name","source_id","source_type"]
610
- when 'admin/apps_new'.to_sym; list_query={:organization_apps=>true};default_fields=['app_type','available']
611
- when 'admin/client_registration_token'.to_sym; default_fields=['id','value','data.client_subject_scopes','created_at']
610
+ when :apps_new; list_query={:organization_apps=>true};default_fields=['app_type','available']
611
+ when :client_registration_token; default_fields=['id','value','data.client_subject_scopes','created_at']
612
612
  end
613
- result=@api_aoc.read(resource_class_path,url_query(list_query))
614
- self.format.display_status("Items: #{result[:data].length}/#{result[:http]['X-Total-Count']}")
613
+ result=@api_aoc.read(resource_class_path,option_url_query(list_query))
614
+ count_msg="Items: #{result[:data].length}/#{result[:http]['X-Total-Count']}"
615
+ count_msg=count_msg.bg_red unless result[:data].length.eql?(result[:http]['X-Total-Count'].to_i)
616
+ self.format.display_status(count_msg)
615
617
  return {:type=>:object_list,:data=>result[:data],:fields=>default_fields}
616
618
  when :show
617
619
  object=@api_aoc.read(resource_instance_path)[:data]
@@ -634,23 +636,11 @@ module Aspera
634
636
  return Main.result_success
635
637
  when :v3,:v4
636
638
  res_data=@api_aoc.read(resource_instance_path)[:data]
637
- find_ak_secret(res_data['access_key'])
638
639
  api_node=@api_aoc.get_node_api(res_data)
639
640
  return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action if command.eql?(:v3)
640
641
  ak_data=api_node.call({:operation=>'GET',:subpath=>"access_keys/#{res_data['access_key']}",:headers=>{'Accept'=>'application/json'}})[:data]
641
- return node_gen4_execute_action({node_info: res_data, file_id: ak_data['root_file_id']})
642
- # when :info
643
- # object=@api_aoc.read(resource_instance_path)[:data]
644
- # access_key=object['access_key']
645
- # match_list=@api_aoc.read('admin/search_nodes',{:q=>"access_key:\"#{access_key}\""})[:data]
646
- # result=match_list.select{|i|i["_source"]["access_key_recursive_counts"].first["access_key"].eql?(access_key)}
647
- # return Main.result_status('Private node') if result.empty?
648
- # raise CliError,"more than one match" unless result.length.eql?(1)
649
- # result=result.first["_source"]
650
- # result.merge!(result['access_key_recursive_counts'].first)
651
- # result.delete('access_key_recursive_counts')
652
- # result.delete('token')
653
- # return { :type=>:single_object, :data =>result}
642
+ command_repo=self.options.get_next_command(NODE4_COMMANDS)
643
+ return execute_node_gen4_command(command_repo,{node_info: res_data, file_id: ak_data['root_file_id']})
654
644
  when :shared_folders
655
645
  read_params = case resource_type
656
646
  when :workspace;{'access_id'=>"ASPERA_ACCESS_KEY_ADMIN_WS_#{res_id}",'access_type'=>'user'}
@@ -661,26 +651,59 @@ module Aspera
661
651
  fields=case resource_type
662
652
  when :node;['id','file_id','file.path','access_type']
663
653
  when :workspace;['id','node_id','file_id','node_name','file.path','tags.aspera.files.workspace.share_as']
664
- else raise "error"
654
+ else raise "unexpected resource type #{resource_type}"
665
655
  end
666
656
  return { :type=>:object_list, :data =>res_data , :fields=>fields}
667
- else raise :ERROR
657
+ when :shared_create
658
+ # TODO
659
+ folder_path=self.options.get_next_argument('folder path in node')
660
+ user_create_data=self.options.get_next_argument('creation data (Hash)')
661
+ res_data=@api_aoc.read(resource_instance_path)[:data]
662
+ node_file = @api_aoc.resolve_node_file({node_info: res_data, file_id: ak_data['root_file_id']},folder_path)
663
+
664
+ #node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
665
+ #file_info = node_api.read("files/#{node_file[:file_id]}")[:data]
666
+
667
+ access_id="ASPERA_ACCESS_KEY_ADMIN_WS_#{@workspace_id}"
668
+ create_data={
669
+ 'file_id' =>node_file[:file_id],
670
+ 'access_type' =>'user',
671
+ 'access_id' =>access_id,
672
+ 'access_levels'=>['list','read','write','delete','mkdir','rename','preview'],
673
+ 'tags' =>{'aspera'=>{'files'=>{'workspace'=>{
674
+ 'id' =>@workspace_id,
675
+ 'workspace_name' =>@workspace_name,
676
+ 'share_as' =>File.basename(folder_path),
677
+ 'user_name' =>c_user_info['name'],
678
+ 'shared_by_user_id'=>c_user_info['id'],
679
+ 'shared_by_name' =>c_user_info['name'],
680
+ 'shared_by_email' =>c_user_info['email'],
681
+ 'shared_with_name' =>access_id,
682
+ 'access_key' =>node_file[:node_info]['access_key'],
683
+ 'node' =>node_file[:node_info]['name']}
684
+ }}}}
685
+ create_data.deep_merge!(user_create_data)
686
+ Log.dump(:data,create_data)
687
+ raise :ERROR
688
+ else raise "unknown command"
668
689
  end
669
690
  when :usage_reports
670
- return {:type=>:object_list,:data=>@api_aoc.read("usage_reports",{:workspace_id=>@workspace_id})[:data]}
691
+ return {:type=>:object_list,:data=>@api_aoc.read('usage_reports',{:workspace_id=>@workspace_id})[:data]}
671
692
  end
672
693
  end
673
694
 
674
- ACTIONS=[ :apiinfo, :bearer_token, :organization, :tier_restrictions, :user, :workspace, :packages, :files, :gateway, :admin, :automation, :servers]
695
+ # must be public
696
+ ACTIONS=[ :reminder, :bearer_token, :organization, :tier_restrictions, :user, :workspace, :packages, :files, :gateway, :admin, :automation, :servers]
675
697
 
676
698
  def execute_action
677
699
  command=self.options.get_next_command(ACTIONS)
700
+ get_api unless [:reminder,:servers].include?(command)
678
701
  case command
679
- when :apiinfo
680
- api_info={}
681
- num=1
682
- Resolv::DNS.open{|dns|dns.each_address('api.ibmaspera.com'){|a| api_info["api.#{num}"]=a;num+=1}}
683
- return {:type=>:single_object,:data=>api_info}
702
+ when :reminder
703
+ # send an email reminder with list of orgs
704
+ user_email=options.get_option(:username,:mandatory)
705
+ Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders',{email: user_email})[:data]
706
+ return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
684
707
  when :bearer_token
685
708
  return {:type=>:text,:data=>@api_aoc.oauth_token}
686
709
  when :organization
@@ -691,23 +714,23 @@ module Aspera
691
714
  command=self.options.get_next_command([ :workspaces,:info,:shared_inboxes ])
692
715
  case command
693
716
  when :workspaces
694
- return {:type=>:object_list,:data=>@api_aoc.read("workspaces")[:data],:fields=>['id','name']}
717
+ return {:type=>:object_list,:data=>@api_aoc.read('workspaces')[:data],:fields=>['id','name']}
695
718
  # when :settings
696
719
  # return {:type=>:object_list,:data=>@api_aoc.read("client_settings/")[:data]}
697
720
  when :shared_inboxes
698
- query=url_query(nil)
721
+ query=option_url_query(nil)
699
722
  if query.nil?
700
723
  set_workspace_info
701
724
  query={'embed[]'=>'dropbox','workspace_id'=>@workspace_id,'aggregate_permissions_by_dropbox'=>true,'sort'=>'dropbox_name'}
702
725
  end
703
- return {:type=>:object_list,:data=>@api_aoc.read("dropbox_memberships",query)[:data],:fields=>['dropbox_id','dropbox.name']}
726
+ return {:type=>:object_list,:data=>@api_aoc.read('dropbox_memberships',query)[:data],:fields=>['dropbox_id','dropbox.name']}
704
727
  when :info
705
728
  command=self.options.get_next_command([ :show,:modify ])
706
729
  case command
707
730
  when :show
708
- return { :type=>:single_object, :data =>user_info }
731
+ return { :type=>:single_object, :data =>c_user_info }
709
732
  when :modify
710
- @api_aoc.update("users/#{user_info['id']}",self.options.get_next_argument('modified parameters (hash)'))
733
+ @api_aoc.update("users/#{c_user_info['id']}",self.options.get_next_argument('modified parameters (hash)'))
711
734
  return Main.result_status('modified')
712
735
  end
713
736
  end
@@ -720,7 +743,7 @@ module Aspera
720
743
  case command_pkg
721
744
  when :send
722
745
  package_creation=self.options.get_option(:value,:mandatory)
723
- raise CliBadArgument,"value must be hash, refer to doc" unless package_creation.is_a?(Hash)
746
+ raise CliBadArgument,'value must be hash, refer to doc' unless package_creation.is_a?(Hash)
724
747
 
725
748
  if !@url_token_data.nil?
726
749
  assert_public_link_types(['send_package_to_user','send_package_to_dropbox'])
@@ -801,12 +824,12 @@ module Aspera
801
824
  return { :type=>:single_object, :data =>package_info }
802
825
  when :list
803
826
  # list all packages ('page'=>1,'per_page'=>10,)'sort'=>'-sent_at',
804
- packages=@api_aoc.read("packages",{'archived'=>false,'exclude_dropbox_packages'=>true,'has_content'=>true,'received'=>true,'workspace_id'=>@workspace_id})[:data]
827
+ packages=@api_aoc.read('packages',{'archived'=>false,'exclude_dropbox_packages'=>true,'has_content'=>true,'received'=>true,'workspace_id'=>@workspace_id})[:data]
805
828
  return {:type=>:object_list,:data=>packages,:fields=>['id','name','bytes_transferred']}
806
829
  when :delete
807
830
  list_or_one=self.options.get_option(:id,:mandatory)
808
831
  return do_bulk_operation(list_or_one,'deleted')do|id|
809
- raise "expecting String identifier" unless id.is_a?(String) or id.is_a?(Integer)
832
+ raise 'expecting String identifier' unless id.is_a?(String) or id.is_a?(Integer)
810
833
  @api_aoc.delete("packages/#{id}")[:data]
811
834
  end
812
835
  end
@@ -814,7 +837,6 @@ module Aspera
814
837
  # get workspace related information
815
838
  set_workspace_info
816
839
  set_home_node_file
817
- find_ak_secret(@home_node_file[:node_info]['access_key'],false)
818
840
  command_repo=self.options.get_next_command(NODE4_COMMANDS.clone.concat([:short_link]))
819
841
  case command_repo
820
842
  when *NODE4_COMMANDS; return execute_node_gen4_command(command_repo,@home_node_file)
@@ -827,7 +849,7 @@ module Aspera
827
849
  when 'private'
828
850
  value_option={'purpose'=>'shared_folder_auth_link'}
829
851
  when NilClass,Hash
830
- else raise "value must be either: public, private, Hash or nil"
852
+ else raise 'value must be either: public, private, Hash or nil'
831
853
  end
832
854
  create_params=nil
833
855
  node_file=nil
@@ -855,30 +877,33 @@ module Aspera
855
877
  }
856
878
  value_option['user_selected_name']=nil
857
879
  else
858
- raise "purpose must be one of: token_auth_redirection or shared_folder_auth_link"
880
+ raise 'purpose must be one of: token_auth_redirection or shared_folder_auth_link'
859
881
  end
860
882
  self.options.set_option(:value,value_option)
861
883
  end
862
884
  result=self.entity_action(@api_aoc,'short_links',nil,:id,'self')
863
885
  if result[:data].is_a?(Hash) and result[:data].has_key?('created_at') and result[:data]['resource_type'].eql?('UrlToken')
864
886
  node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
887
+ # TODO: access level as arg
888
+ access_levels=Aspera::Node::ACCESS_LEVELS #['delete','list','mkdir','preview','read','rename','write']
865
889
  perm_data={
866
- "file_id" =>node_file[:file_id],
867
- "access_type" =>"user",
868
- "access_id" =>result[:data]['resource_id'],
869
- "access_levels"=>["delete","list","mkdir","preview","read","rename","write"],
870
- "tags" =>{
871
- "url_token" =>true,
872
- "workspace_id" =>@workspace_id,
873
- "workspace_name" =>@workspace_name,
874
- "folder_name" =>"my folder",
875
- "created_by_name" =>user_info['name'],
876
- "created_by_email"=>user_info['email'],
877
- "access_key" =>node_file[:node_info]['access_key'],
878
- "node" =>node_file[:node_info]['host']
890
+ 'file_id' =>node_file[:file_id],
891
+ 'access_type' =>'user',
892
+ 'access_id' =>result[:data]['resource_id'],
893
+ 'access_levels'=>access_levels,
894
+ 'tags' =>{
895
+ 'url_token' =>true,
896
+ 'workspace_id' =>@workspace_id,
897
+ 'workspace_name' =>@workspace_name,
898
+ 'folder_name' =>'my folder',
899
+ 'created_by_name' =>c_user_info['name'],
900
+ 'created_by_email'=>c_user_info['email'],
901
+ 'access_key' =>node_file[:node_info]['access_key'],
902
+ 'node' =>node_file[:node_info]['host']
879
903
  }
880
904
  }
881
905
  node_api.create("permissions?file_id=#{node_file[:file_id]}",perm_data)
906
+ # TODO: event ?
882
907
  end
883
908
  return result
884
909
  end # files command
@@ -921,17 +946,17 @@ module Aspera
921
946
  when :admin
922
947
  return execute_admin_action
923
948
  when :servers
924
- self.format.display_status("Beta feature")
925
- server_api=Rest.new(base_url: 'https://eudemo.asperademo.com')
926
- require 'json'
927
- servers=JSON.parse(server_api.read('servers')[:data])
928
- return {:type=>:object_list,:data=>servers}
949
+ return {:type=>:object_list,:data=>Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
929
950
  else
930
951
  raise "internal error: #{command}"
931
952
  end # action
932
953
  raise RuntimeError, "internal error: command shall return"
933
954
  end
934
- end # Aspera
955
+
956
+ private :c_user_info,: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
957
+ private_constant :VAL_ALL,:NODE4_COMMANDS
958
+
959
+ end # AoC
935
960
  end # Plugins
936
961
  end # Cli
937
962
  end # Aspera