aspera-cli 4.0.0 → 4.2.2

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +843 -304
  3. data/bin/dascli +13 -0
  4. data/docs/Makefile +4 -4
  5. data/docs/README.erb.md +805 -172
  6. data/docs/test_env.conf +22 -3
  7. data/examples/aoc.rb +14 -3
  8. data/examples/faspex4.rb +89 -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 +89 -49
  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 +188 -173
  15. data/lib/aspera/cli/plugins/ats.rb +2 -2
  16. data/lib/aspera/cli/plugins/config.rb +218 -145
  17. data/lib/aspera/cli/plugins/console.rb +2 -2
  18. data/lib/aspera/cli/plugins/faspex.rb +114 -61
  19. data/lib/aspera/cli/plugins/faspex5.rb +85 -43
  20. data/lib/aspera/cli/plugins/node.rb +3 -3
  21. data/lib/aspera/cli/plugins/preview.rb +59 -45
  22. data/lib/aspera/cli/plugins/server.rb +23 -8
  23. data/lib/aspera/cli/transfer_agent.rb +77 -49
  24. data/lib/aspera/cli/version.rb +1 -1
  25. data/lib/aspera/command_line_builder.rb +49 -31
  26. data/lib/aspera/cos_node.rb +33 -28
  27. data/lib/aspera/environment.rb +2 -2
  28. data/lib/aspera/fasp/connect.rb +28 -21
  29. data/lib/aspera/fasp/http_gw.rb +140 -28
  30. data/lib/aspera/fasp/installation.rb +93 -46
  31. data/lib/aspera/fasp/local.rb +88 -45
  32. data/lib/aspera/fasp/manager.rb +15 -0
  33. data/lib/aspera/fasp/node.rb +4 -4
  34. data/lib/aspera/fasp/parameters.rb +59 -101
  35. data/lib/aspera/fasp/parameters.yaml +531 -0
  36. data/lib/aspera/fasp/resume_policy.rb +13 -12
  37. data/lib/aspera/fasp/uri.rb +1 -1
  38. data/lib/aspera/log.rb +1 -1
  39. data/lib/aspera/node.rb +61 -1
  40. data/lib/aspera/oauth.rb +49 -46
  41. data/lib/aspera/persistency_folder.rb +9 -4
  42. data/lib/aspera/preview/file_types.rb +53 -21
  43. data/lib/aspera/preview/generator.rb +3 -3
  44. data/lib/aspera/rest.rb +29 -18
  45. data/lib/aspera/secrets.rb +20 -0
  46. data/lib/aspera/sync.rb +40 -35
  47. data/lib/aspera/temp_file_manager.rb +19 -0
  48. data/lib/aspera/web_auth.rb +105 -0
  49. metadata +54 -20
  50. data/docs/transfer_spec.html +0 -99
@@ -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,22 @@ 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_boolean(:bulk,'bulk operation')
43
+ self.options.add_opt_boolean(:default_ports,'use standard FASP ports or get from node api')
45
44
  self.options.set_option(:bulk,:no)
46
45
  self.options.set_option(:default_ports,:yes)
47
46
  self.options.set_option(:new_user_option,{'package_contact'=>true})
@@ -52,20 +51,19 @@ module Aspera
52
51
  self.options.parse_options!
53
52
  AoC.set_use_default_ports(self.options.get_option(:default_ports))
54
53
  return if env[:man_only]
55
- update_aoc_api
56
54
  end
57
55
 
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
56
+ def get_api
57
+ if @api_aoc.nil?
58
+ @api_aoc=AoC.new(aoc_params(AoC::API_V1))
59
+ # add keychain for access key secrets
60
+ @api_aoc.key_chain=@agents[:secret]
61
+ end
62
+ return @api_aoc
66
63
  end
67
64
 
68
- def user_info
65
+ # cached user information
66
+ def c_user_info
69
67
  if @user_info.nil?
70
68
  # get our user's default information
71
69
  # self?embed[]=default_workspace&embed[]=organization
@@ -80,16 +78,11 @@ module Aspera
80
78
  # starts transfer using transfer agent
81
79
  def transfer_start(app,direction,node_file,ts_add)
82
80
  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']))
81
+ ts_add.deep_merge!(AoC.console_ts(app,c_user_info['name'],c_user_info['email']))
84
82
  return self.transfer.start(*@api_aoc.tr_spec(app,direction,node_file,ts_add))
85
83
  end
86
84
 
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
85
+ NODE4_COMMANDS=[ :browse, :find, :mkdir, :rename, :delete, :upload, :download, :transfer, :http_node_download, :v3, :file, :bearer_token_node ]
93
86
 
94
87
  def execute_node_gen4_command(command_repo,top_node_file)
95
88
  case command_repo
@@ -113,14 +106,8 @@ module Aspera
113
106
  return {:type=>:object_list,:data=>items,:fields=>['name','type','recursive_size','size','modified_time','access_level']}
114
107
  when :find
115
108
  thepath=self.options.get_next_argument('path')
116
- exec_prefix='exec:'
117
- expression=self.options.get_option(:value,:optional)||"#{exec_prefix}true"
118
109
  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
110
+ test_block=Aspera::Node.file_matcher(self.options.get_option(:value,:optional))
124
111
  return {:type=>:object_list,:data=>@api_aoc.find_files(node_file,test_block),:fields=>['path']}
125
112
  when :mkdir
126
113
  thepath=self.options.get_next_argument('path')
@@ -213,69 +200,79 @@ module Aspera
213
200
  node_api=@api_aoc.get_node_api(top_node_file[:node_info],AoC::SCOPE_NODE_USER)
214
201
  return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: node_api)).execute_action(command_legacy)
215
202
  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)
203
+ file_path=self.options.get_option(:path,:optional)
204
+ node_file = if !file_path.nil?
205
+ @api_aoc.resolve_node_file(top_node_file,file_path) # TODO: allow follow link ?
206
+ else
207
+ {node_info: top_node_file[:node_info],file_id: self.options.get_option(:id,:mandatory)}
208
+ end
224
209
  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
210
+ command_node_file=self.options.get_next_command([:show,:permission,:modify])
211
+ case command_node_file
227
212
  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"
213
+ items=node_api.read("files/#{node_file[:file_id]}")[:data]
214
+ return {:type=>:single_object,:data=>items}
215
+ when :modify
216
+ update_param=self.options.get_next_argument("update data (Hash)")
217
+ res=node_api.update("files/#{node_file[:file_id]}",update_param)[:data]
218
+ return {:type=>:single_object,:data=>res}
219
+ when :permission
220
+ command_perm=self.options.get_next_command([:list,:create])
221
+ case command_perm
222
+ when :list
223
+ # generic options : TODO: as arg ?
224
+ list_options||={'include'=>['[]','access_level','permission_count']}
225
+ # special value: ALL will show all permissions
226
+ if !VAL_ALL.eql?(node_file[:file_id])
227
+ # add which one to get
228
+ list_options['file_id']=node_file[:file_id]
229
+ list_options['inherited']||=false
230
+ end
231
+ #option_url_query
232
+ items=node_api.read('permissions',list_options)[:data]
233
+ return {:type=>:object_list,:data=>items}
234
+ when :create
235
+ #create_param=self.options.get_next_argument("creation data (Hash)")
236
+ set_workspace_info
237
+ access_id="ASPERA_ACCESS_KEY_ADMIN_WS_#{@workspace_id}"
238
+ node_file[:node_info]
239
+ params={
240
+ 'file_id' =>node_file[:file_id], # mandatory
241
+ 'access_type' =>'user', # mandatory: user or group
242
+ 'access_id' =>access_id, # id of user or group
243
+ 'access_levels'=>Aspera::Node::ACCESS_LEVELS,
244
+ 'tags' =>{'aspera'=>{'files'=>{'workspace'=>{
245
+ 'id' =>@workspace_id,
246
+ 'workspace_name' =>@workspace_name,
247
+ 'user_name' =>c_user_info['name'],
248
+ 'shared_by_user_id'=>c_user_info['id'],
249
+ 'shared_by_name' =>c_user_info['name'],
250
+ 'shared_by_email' =>c_user_info['email'],
251
+ 'shared_with_name' =>access_id,
252
+ 'access_key' =>node_file[:node_info]['access_key'],
253
+ 'node' =>node_file[:node_info]['name']}}}}}
254
+ item=node_api.create('permissions',params)[:data]
255
+ return {:type=>:single_object,:data=>item}
256
+ else raise "internal error:shall not reach here (#{command_perm})"
257
+ end
258
+ raise "internal error:shall not reach here"
259
+ else raise "internal error:shall not reach here (#{command_node_file})"
256
260
  end
261
+ raise "internal error:shall not reach here"
262
+ when :permissions
263
+
257
264
  end # command_repo
258
- throw "ERR"
265
+ raise "ERR"
259
266
  end # execute_node_gen4_command
260
267
 
261
268
  # build constructor option list for AoC based on options of CLI
262
269
  def aoc_params(subpath)
263
270
  # 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}
271
+ 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
272
  opt[:subpath]=subpath
266
273
  return opt
267
274
  end
268
275
 
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
276
  # initialize apis and authentication
280
277
  # set:
281
278
  # @default_workspace_id
@@ -290,8 +287,8 @@ module Aspera
290
287
  @default_workspace_id=@url_token_data['data']['workspace_id']
291
288
  @persist_ids=[] # TODO : @url_token_data['id'] ?
292
289
  else
293
- @default_workspace_id=user_info['default_workspace_id']
294
- @persist_ids=[user_info['id']]
290
+ @default_workspace_id=c_user_info['default_workspace_id']
291
+ @persist_ids=[c_user_info['id']]
295
292
  end
296
293
 
297
294
  ws_name=self.options.get_option(:workspace,:optional)
@@ -401,7 +398,8 @@ module Aspera
401
398
  package_creation[recipient_list_field]=resolved_list
402
399
  end
403
400
 
404
- def url_query(default)
401
+ # private
402
+ def option_url_query(default)
405
403
  query=self.options.get_option(:query,:optional)||default
406
404
  Log.log.debug("Query=#{query}".bg_red)
407
405
  begin
@@ -420,8 +418,7 @@ module Aspera
420
418
  end
421
419
 
422
420
  def execute_admin_action
423
- self.options.set_option(:scope,AoC::SCOPE_FILES_ADMIN)
424
- update_aoc_api
421
+ @api_aoc.oauth.params[:scope]=AoC::SCOPE_FILES_ADMIN
425
422
  command_admin=self.options.get_next_command([ :ats, :resource, :usage_reports, :analytics, :subscription, :auth_providers ])
426
423
  case command_admin
427
424
  when :auth_providers
@@ -490,20 +487,7 @@ module Aspera
490
487
  :base_url => @api_aoc.params[:base_url]+'/admin/ats/pub/v1',
491
488
  :auth => {:scope => AoC::SCOPE_FILES_ADMIN_USER}
492
489
  }))
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']}
490
+ return Ats.new(@agents).execute_action_gen(ats_api)
507
491
  when :analytics
508
492
  analytics_api = Rest.new(@api_aoc.params.deep_merge({
509
493
  :base_url => @api_aoc.params[:base_url].gsub('/api/v1','')+'/analytics/v2',
@@ -513,19 +497,20 @@ module Aspera
513
497
  case command_analytics
514
498
  when :application_events
515
499
  event_type=command_analytics.to_s
516
- events=analytics_api.read("organizations/#{user_info['organization_id']}/#{event_type}")[:data][event_type]
500
+ events=analytics_api.read("organizations/#{c_user_info['organization_id']}/#{event_type}")[:data][event_type]
517
501
  return {:type=>:object_list,:data=>events}
518
502
  when :transfers
519
503
  event_type=command_analytics.to_s
520
504
  filter_resource=self.options.get_option(:name,:optional) || 'organizations'
521
505
  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']
506
+ when 'organizations'; c_user_info['organization_id']
507
+ when 'users'; c_user_info['id']
508
+ when 'nodes'; c_user_info['id']
525
509
  else raise "organizations or users for option --name"
526
510
  end
527
511
  #
528
512
  filter=self.options.get_option(:query,:optional) || {}
513
+ raise "query must be Hash" unless filter.is_a?(Hash)
529
514
  filter['limit']||=100
530
515
  if self.options.get_option(:once_only,:mandatory)
531
516
  saved_date=[]
@@ -541,18 +526,11 @@ module Aspera
541
526
  filter['start_time'] = start_datetime unless start_datetime.nil?
542
527
  filter['stop_time'] = stop_datetime
543
528
  end
544
- notification=self.options.get_option(:notify,:optional)
545
- events=analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}",url_query(filter))[:data][event_type]
529
+ events=analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}",option_url_query(filter))[:data][event_type]
546
530
  startdate_persistency.save unless startdate_persistency.nil?
547
- if !notification.nil?
548
- require 'erb'
549
- events.each do |transfer|
550
- email_to_send={}
551
- notification.each do |k,v|
552
- email_to_send[k.to_sym]=ERB.new(v).result(binding)
553
- end
554
- Log.log().error("send email: #{email_to_send}")
555
- self.config.send_email(email_to_send)
531
+ if !self.options.get_option(:notif_to,:optional).nil?
532
+ events.each do |tr_event|
533
+ self.config.send_email_template({ev: tr_event})
556
534
  end
557
535
  end
558
536
  return {:type=>:object_list,:data=>events}
@@ -581,7 +559,7 @@ module Aspera
581
559
  supported_operations.push(:delete,*global_operations) unless singleton_object
582
560
  supported_operations.push(:v4,:v3) if resource_type.eql?(:node)
583
561
  supported_operations.push(:set_pub_key) if resource_type.eql?(:client)
584
- supported_operations.push(:shared_folders) if [:node,:workspace].include?(resource_type)
562
+ supported_operations.push(:shared_folders,:shared_create) if [:node,:workspace].include?(resource_type)
585
563
  command=self.options.get_next_command(supported_operations)
586
564
  # require identifier for non global commands
587
565
  if !singleton_object and !global_operations.include?(command)
@@ -624,8 +602,10 @@ module Aspera
624
602
  when :apps_new; list_query={:organization_apps=>true};default_fields=['app_type','available']
625
603
  when :client_registration_token; default_fields=['id','value','data.client_subject_scopes','created_at']
626
604
  end
627
- result=@api_aoc.read(resource_class_path,url_query(list_query))
628
- self.format.display_status("Items: #{result[:data].length}/#{result[:http]['X-Total-Count']}")
605
+ result=@api_aoc.read(resource_class_path,option_url_query(list_query))
606
+ count_msg="Items: #{result[:data].length}/#{result[:http]['X-Total-Count']}"
607
+ count_msg=count_msg.bg_red unless result[:data].length.eql?(result[:http]['X-Total-Count'].to_i)
608
+ self.format.display_status(count_msg)
629
609
  return {:type=>:object_list,:data=>result[:data],:fields=>default_fields}
630
610
  when :show
631
611
  object=@api_aoc.read(resource_instance_path)[:data]
@@ -648,11 +628,11 @@ module Aspera
648
628
  return Main.result_success
649
629
  when :v3,:v4
650
630
  res_data=@api_aoc.read(resource_instance_path)[:data]
651
- find_ak_secret(res_data['access_key'])
652
631
  api_node=@api_aoc.get_node_api(res_data)
653
632
  return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action if command.eql?(:v3)
654
633
  ak_data=api_node.call({:operation=>'GET',:subpath=>"access_keys/#{res_data['access_key']}",:headers=>{'Accept'=>'application/json'}})[:data]
655
- return node_gen4_execute_action({node_info: res_data, file_id: ak_data['root_file_id']})
634
+ command_repo=self.options.get_next_command(NODE4_COMMANDS)
635
+ return execute_node_gen4_command(command_repo,{node_info: res_data, file_id: ak_data['root_file_id']})
656
636
  when :shared_folders
657
637
  read_params = case resource_type
658
638
  when :workspace;{'access_id'=>"ASPERA_ACCESS_KEY_ADMIN_WS_#{res_id}",'access_type'=>'user'}
@@ -663,26 +643,59 @@ module Aspera
663
643
  fields=case resource_type
664
644
  when :node;['id','file_id','file.path','access_type']
665
645
  when :workspace;['id','node_id','file_id','node_name','file.path','tags.aspera.files.workspace.share_as']
666
- else raise "error"
646
+ else raise "unexpected resource type #{resource_type}"
667
647
  end
668
648
  return { :type=>:object_list, :data =>res_data , :fields=>fields}
669
- else raise :ERROR
649
+ when :shared_create
650
+ # TODO
651
+ folder_path=self.options.get_next_argument('folder path in node')
652
+ user_create_data=self.options.get_next_argument('creation data (Hash)')
653
+ res_data=@api_aoc.read(resource_instance_path)[:data]
654
+ node_file = @api_aoc.resolve_node_file({node_info: res_data, file_id: ak_data['root_file_id']},folder_path)
655
+
656
+ #node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
657
+ #file_info = node_api.read("files/#{node_file[:file_id]}")[:data]
658
+
659
+ access_id="ASPERA_ACCESS_KEY_ADMIN_WS_#{@workspace_id}"
660
+ create_data={
661
+ 'file_id' =>node_file[:file_id],
662
+ 'access_type' =>'user',
663
+ 'access_id' =>access_id,
664
+ 'access_levels'=>['list','read','write','delete','mkdir','rename','preview'],
665
+ 'tags' =>{'aspera'=>{'files'=>{'workspace'=>{
666
+ 'id' =>@workspace_id,
667
+ 'workspace_name' =>@workspace_name,
668
+ 'share_as' =>File.basename(folder_path),
669
+ 'user_name' =>c_user_info['name'],
670
+ 'shared_by_user_id'=>c_user_info['id'],
671
+ 'shared_by_name' =>c_user_info['name'],
672
+ 'shared_by_email' =>c_user_info['email'],
673
+ 'shared_with_name' =>access_id,
674
+ 'access_key' =>node_file[:node_info]['access_key'],
675
+ 'node' =>node_file[:node_info]['name']}
676
+ }}}}
677
+ create_data.deep_merge!(user_create_data)
678
+ Log.dump(:data,create_data)
679
+ raise :ERROR
680
+ else raise "unknown command"
670
681
  end
671
682
  when :usage_reports
672
- return {:type=>:object_list,:data=>@api_aoc.read("usage_reports",{:workspace_id=>@workspace_id})[:data]}
683
+ return {:type=>:object_list,:data=>@api_aoc.read('usage_reports',{:workspace_id=>@workspace_id})[:data]}
673
684
  end
674
685
  end
675
686
 
676
- ACTIONS=[ :apiinfo, :bearer_token, :organization, :tier_restrictions, :user, :workspace, :packages, :files, :gateway, :admin, :automation, :servers]
687
+ # must be public
688
+ ACTIONS=[ :reminder, :bearer_token, :organization, :tier_restrictions, :user, :workspace, :packages, :files, :gateway, :admin, :automation, :servers]
677
689
 
678
690
  def execute_action
679
691
  command=self.options.get_next_command(ACTIONS)
692
+ get_api unless [:reminder,:servers].include?(command)
680
693
  case command
681
- when :apiinfo
682
- api_info={}
683
- num=1
684
- Resolv::DNS.open{|dns|dns.each_address('api.ibmaspera.com'){|a| api_info["api.#{num}"]=a;num+=1}}
685
- return {:type=>:single_object,:data=>api_info}
694
+ when :reminder
695
+ # send an email reminder with list of orgs
696
+ user_email=options.get_option(:username,:mandatory)
697
+ Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders',{email: user_email})[:data]
698
+ return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
686
699
  when :bearer_token
687
700
  return {:type=>:text,:data=>@api_aoc.oauth_token}
688
701
  when :organization
@@ -693,23 +706,23 @@ module Aspera
693
706
  command=self.options.get_next_command([ :workspaces,:info,:shared_inboxes ])
694
707
  case command
695
708
  when :workspaces
696
- return {:type=>:object_list,:data=>@api_aoc.read("workspaces")[:data],:fields=>['id','name']}
709
+ return {:type=>:object_list,:data=>@api_aoc.read('workspaces')[:data],:fields=>['id','name']}
697
710
  # when :settings
698
711
  # return {:type=>:object_list,:data=>@api_aoc.read("client_settings/")[:data]}
699
712
  when :shared_inboxes
700
- query=url_query(nil)
713
+ query=option_url_query(nil)
701
714
  if query.nil?
702
715
  set_workspace_info
703
716
  query={'embed[]'=>'dropbox','workspace_id'=>@workspace_id,'aggregate_permissions_by_dropbox'=>true,'sort'=>'dropbox_name'}
704
717
  end
705
- return {:type=>:object_list,:data=>@api_aoc.read("dropbox_memberships",query)[:data],:fields=>['dropbox_id','dropbox.name']}
718
+ return {:type=>:object_list,:data=>@api_aoc.read('dropbox_memberships',query)[:data],:fields=>['dropbox_id','dropbox.name']}
706
719
  when :info
707
720
  command=self.options.get_next_command([ :show,:modify ])
708
721
  case command
709
722
  when :show
710
- return { :type=>:single_object, :data =>user_info }
723
+ return { :type=>:single_object, :data =>c_user_info }
711
724
  when :modify
712
- @api_aoc.update("users/#{user_info['id']}",self.options.get_next_argument('modified parameters (hash)'))
725
+ @api_aoc.update("users/#{c_user_info['id']}",self.options.get_next_argument('modified parameters (hash)'))
713
726
  return Main.result_status('modified')
714
727
  end
715
728
  end
@@ -722,7 +735,7 @@ module Aspera
722
735
  case command_pkg
723
736
  when :send
724
737
  package_creation=self.options.get_option(:value,:mandatory)
725
- raise CliBadArgument,"value must be hash, refer to doc" unless package_creation.is_a?(Hash)
738
+ raise CliBadArgument,'value must be hash, refer to doc' unless package_creation.is_a?(Hash)
726
739
 
727
740
  if !@url_token_data.nil?
728
741
  assert_public_link_types(['send_package_to_user','send_package_to_dropbox'])
@@ -789,26 +802,26 @@ module Aspera
789
802
  add_ts={'paths'=>[{'source'=>'.'}]}
790
803
  node_file = {node_info: node_info, file_id: package_info['contents_file_id']}
791
804
  statuses=transfer_start(AoC::PACKAGES_APP,'receive',node_file,AoC.package_tags(package_info,'download').merge(add_ts))
792
- result_transfer.push({'package'=>package_id,'status'=>statuses.map{|i|i.to_s}.join(',')})
805
+ result_transfer.push({'package'=>package_id,Main::STATUS_FIELD=>statuses})
793
806
  # update skip list only if all transfer sessions completed
794
807
  if TransferAgent.session_status(statuses).eql?(:success)
795
808
  skip_ids_data.push(package_id)
796
809
  skip_ids_persistency.save unless skip_ids_persistency.nil?
797
810
  end
798
811
  end
799
- return {:type=>:object_list,:data=>result_transfer}
812
+ return Main.result_transfer_multiple(result_transfer)
800
813
  when :show
801
814
  package_id=self.options.get_next_argument('package ID')
802
815
  package_info=@api_aoc.read("packages/#{package_id}")[:data]
803
816
  return { :type=>:single_object, :data =>package_info }
804
817
  when :list
805
818
  # list all packages ('page'=>1,'per_page'=>10,)'sort'=>'-sent_at',
806
- packages=@api_aoc.read("packages",{'archived'=>false,'exclude_dropbox_packages'=>true,'has_content'=>true,'received'=>true,'workspace_id'=>@workspace_id})[:data]
819
+ packages=@api_aoc.read('packages',{'archived'=>false,'exclude_dropbox_packages'=>true,'has_content'=>true,'received'=>true,'workspace_id'=>@workspace_id})[:data]
807
820
  return {:type=>:object_list,:data=>packages,:fields=>['id','name','bytes_transferred']}
808
821
  when :delete
809
822
  list_or_one=self.options.get_option(:id,:mandatory)
810
823
  return do_bulk_operation(list_or_one,'deleted')do|id|
811
- raise "expecting String identifier" unless id.is_a?(String) or id.is_a?(Integer)
824
+ raise 'expecting String identifier' unless id.is_a?(String) or id.is_a?(Integer)
812
825
  @api_aoc.delete("packages/#{id}")[:data]
813
826
  end
814
827
  end
@@ -816,7 +829,6 @@ module Aspera
816
829
  # get workspace related information
817
830
  set_workspace_info
818
831
  set_home_node_file
819
- find_ak_secret(@home_node_file[:node_info]['access_key'],false)
820
832
  command_repo=self.options.get_next_command(NODE4_COMMANDS.clone.concat([:short_link]))
821
833
  case command_repo
822
834
  when *NODE4_COMMANDS; return execute_node_gen4_command(command_repo,@home_node_file)
@@ -829,7 +841,7 @@ module Aspera
829
841
  when 'private'
830
842
  value_option={'purpose'=>'shared_folder_auth_link'}
831
843
  when NilClass,Hash
832
- else raise "value must be either: public, private, Hash or nil"
844
+ else raise 'value must be either: public, private, Hash or nil'
833
845
  end
834
846
  create_params=nil
835
847
  node_file=nil
@@ -857,30 +869,33 @@ module Aspera
857
869
  }
858
870
  value_option['user_selected_name']=nil
859
871
  else
860
- raise "purpose must be one of: token_auth_redirection or shared_folder_auth_link"
872
+ raise 'purpose must be one of: token_auth_redirection or shared_folder_auth_link'
861
873
  end
862
874
  self.options.set_option(:value,value_option)
863
875
  end
864
876
  result=self.entity_action(@api_aoc,'short_links',nil,:id,'self')
865
877
  if result[:data].is_a?(Hash) and result[:data].has_key?('created_at') and result[:data]['resource_type'].eql?('UrlToken')
866
878
  node_api=@api_aoc.get_node_api(node_file[:node_info],AoC::SCOPE_NODE_USER)
879
+ # TODO: access level as arg
880
+ access_levels=Aspera::Node::ACCESS_LEVELS #['delete','list','mkdir','preview','read','rename','write']
867
881
  perm_data={
868
- "file_id" =>node_file[:file_id],
869
- "access_type" =>"user",
870
- "access_id" =>result[:data]['resource_id'],
871
- "access_levels"=>["delete","list","mkdir","preview","read","rename","write"],
872
- "tags" =>{
873
- "url_token" =>true,
874
- "workspace_id" =>@workspace_id,
875
- "workspace_name" =>@workspace_name,
876
- "folder_name" =>"my folder",
877
- "created_by_name" =>user_info['name'],
878
- "created_by_email"=>user_info['email'],
879
- "access_key" =>node_file[:node_info]['access_key'],
880
- "node" =>node_file[:node_info]['host']
882
+ 'file_id' =>node_file[:file_id],
883
+ 'access_type' =>'user',
884
+ 'access_id' =>result[:data]['resource_id'],
885
+ 'access_levels'=>access_levels,
886
+ 'tags' =>{
887
+ 'url_token' =>true,
888
+ 'workspace_id' =>@workspace_id,
889
+ 'workspace_name' =>@workspace_name,
890
+ 'folder_name' =>'my folder',
891
+ 'created_by_name' =>c_user_info['name'],
892
+ 'created_by_email'=>c_user_info['email'],
893
+ 'access_key' =>node_file[:node_info]['access_key'],
894
+ 'node' =>node_file[:node_info]['host']
881
895
  }
882
896
  }
883
897
  node_api.create("permissions?file_id=#{node_file[:file_id]}",perm_data)
898
+ # TODO: event ?
884
899
  end
885
900
  return result
886
901
  end # files command
@@ -923,17 +938,17 @@ module Aspera
923
938
  when :admin
924
939
  return execute_admin_action
925
940
  when :servers
926
- self.format.display_status("Beta feature")
927
- server_api=Rest.new(base_url: 'https://eudemo.asperademo.com')
928
- require 'json'
929
- servers=JSON.parse(server_api.read('servers')[:data])
930
- return {:type=>:object_list,:data=>servers}
941
+ return {:type=>:object_list,:data=>Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").read('servers')[:data]}
931
942
  else
932
943
  raise "internal error: #{command}"
933
944
  end # action
934
945
  raise RuntimeError, "internal error: command shall return"
935
946
  end
936
- end # Aspera
947
+
948
+ 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
949
+ private_constant :VAL_ALL,:NODE4_COMMANDS
950
+
951
+ end # AoC
937
952
  end # Plugins
938
953
  end # Cli
939
954
  end # Aspera
@@ -107,7 +107,7 @@ module Aspera
107
107
  :auth => {
108
108
  :type => :basic,
109
109
  :username => access_key_id,
110
- :password => self.config.get_secret(access_key_id)}})
110
+ :password => @agents[:secret].get_secret(access_key_id)}})
111
111
  command=self.options.get_next_command(Node::COMMON_ACTIONS)
112
112
  return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command)
113
113
  when :cluster
@@ -116,7 +116,7 @@ module Aspera
116
116
  :auth => {
117
117
  :type => :basic,
118
118
  :username => access_key_id,
119
- :password => self.config.get_secret(access_key_id)
119
+ :password => @agents[:secret].get_secret(access_key_id)
120
120
  }}
121
121
  api_ak_auth=Rest.new(rest_params)
122
122
  return {:type=>:single_object, :data=>api_ak_auth.read("servers")[:data]}