aspera-cli 4.7.0 → 4.8.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 (94) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -0
  3. data/README.md +844 -861
  4. data/bin/ascli +20 -1
  5. data/bin/asession +37 -34
  6. data/docs/test_env.conf +11 -3
  7. data/examples/aoc.rb +13 -12
  8. data/examples/dascli +26 -0
  9. data/examples/faspex4.rb +34 -29
  10. data/examples/transfer.rb +30 -29
  11. data/lib/aspera/aoc.rb +151 -143
  12. data/lib/aspera/ascmd.rb +56 -45
  13. data/lib/aspera/ats_api.rb +6 -5
  14. data/lib/aspera/cli/basic_auth_plugin.rb +18 -16
  15. data/lib/aspera/cli/extended_value.rb +32 -30
  16. data/lib/aspera/cli/formater.rb +103 -111
  17. data/lib/aspera/cli/info.rb +2 -1
  18. data/lib/aspera/cli/listener/line_dump.rb +1 -0
  19. data/lib/aspera/cli/listener/logger.rb +1 -0
  20. data/lib/aspera/cli/listener/progress.rb +13 -12
  21. data/lib/aspera/cli/listener/progress_multi.rb +21 -20
  22. data/lib/aspera/cli/main.rb +106 -89
  23. data/lib/aspera/cli/manager.rb +96 -85
  24. data/lib/aspera/cli/plugin.rb +50 -32
  25. data/lib/aspera/cli/plugins/alee.rb +6 -5
  26. data/lib/aspera/cli/plugins/aoc.rb +521 -426
  27. data/lib/aspera/cli/plugins/ats.rb +84 -83
  28. data/lib/aspera/cli/plugins/bss.rb +30 -27
  29. data/lib/aspera/cli/plugins/config.rb +483 -397
  30. data/lib/aspera/cli/plugins/console.rb +17 -15
  31. data/lib/aspera/cli/plugins/cos.rb +26 -35
  32. data/lib/aspera/cli/plugins/faspex.rb +201 -168
  33. data/lib/aspera/cli/plugins/faspex5.rb +109 -74
  34. data/lib/aspera/cli/plugins/node.rb +378 -189
  35. data/lib/aspera/cli/plugins/orchestrator.rb +71 -65
  36. data/lib/aspera/cli/plugins/preview.rb +131 -122
  37. data/lib/aspera/cli/plugins/server.rb +94 -93
  38. data/lib/aspera/cli/plugins/shares.rb +42 -28
  39. data/lib/aspera/cli/plugins/sync.rb +15 -14
  40. data/lib/aspera/cli/transfer_agent.rb +56 -52
  41. data/lib/aspera/cli/version.rb +2 -1
  42. data/lib/aspera/colors.rb +29 -28
  43. data/lib/aspera/command_line_builder.rb +50 -43
  44. data/lib/aspera/cos_node.rb +64 -38
  45. data/lib/aspera/data_repository.rb +1 -0
  46. data/lib/aspera/environment.rb +18 -8
  47. data/lib/aspera/fasp/agent_base.rb +26 -23
  48. data/lib/aspera/fasp/agent_connect.rb +35 -30
  49. data/lib/aspera/fasp/agent_direct.rb +68 -60
  50. data/lib/aspera/fasp/agent_httpgw.rb +71 -64
  51. data/lib/aspera/fasp/agent_node.rb +24 -23
  52. data/lib/aspera/fasp/agent_trsdk.rb +19 -20
  53. data/lib/aspera/fasp/error.rb +2 -1
  54. data/lib/aspera/fasp/error_info.rb +79 -68
  55. data/lib/aspera/fasp/installation.rb +122 -114
  56. data/lib/aspera/fasp/listener.rb +1 -0
  57. data/lib/aspera/fasp/parameters.rb +44 -41
  58. data/lib/aspera/fasp/resume_policy.rb +14 -11
  59. data/lib/aspera/fasp/transfer_spec.rb +6 -5
  60. data/lib/aspera/fasp/uri.rb +25 -24
  61. data/lib/aspera/faspex_gw.rb +83 -72
  62. data/lib/aspera/hash_ext.rb +10 -12
  63. data/lib/aspera/id_generator.rb +8 -7
  64. data/lib/aspera/keychain/encrypted_hash.rb +60 -45
  65. data/lib/aspera/keychain/macos_security.rb +26 -24
  66. data/lib/aspera/log.rb +34 -38
  67. data/lib/aspera/nagios.rb +14 -13
  68. data/lib/aspera/node.rb +19 -19
  69. data/lib/aspera/oauth.rb +121 -101
  70. data/lib/aspera/open_application.rb +6 -5
  71. data/lib/aspera/persistency_action_once.rb +9 -8
  72. data/lib/aspera/persistency_folder.rb +10 -9
  73. data/lib/aspera/preview/file_types.rb +261 -266
  74. data/lib/aspera/preview/generator.rb +74 -73
  75. data/lib/aspera/preview/image_error.png +0 -0
  76. data/lib/aspera/preview/options.rb +7 -6
  77. data/lib/aspera/preview/utils.rb +30 -33
  78. data/lib/aspera/preview/video_error.png +0 -0
  79. data/lib/aspera/proxy_auto_config.rb +25 -23
  80. data/lib/aspera/rest.rb +73 -74
  81. data/lib/aspera/rest_call_error.rb +1 -0
  82. data/lib/aspera/rest_error_analyzer.rb +11 -9
  83. data/lib/aspera/rest_errors_aspera.rb +5 -4
  84. data/lib/aspera/secret_hider.rb +68 -0
  85. data/lib/aspera/ssh.rb +12 -10
  86. data/lib/aspera/sync.rb +49 -47
  87. data/lib/aspera/temp_file_manager.rb +7 -5
  88. data/lib/aspera/timer_limiter.rb +9 -8
  89. data/lib/aspera/uri_reader.rb +11 -14
  90. data/lib/aspera/web_auth.rb +17 -15
  91. data.tar.gz.sig +0 -0
  92. metadata +117 -34
  93. metadata.gz.sig +2 -0
  94. data/bin/dascli +0 -13
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'aspera/cli/basic_auth_plugin'
3
4
  require 'aspera/cli/plugins/node'
4
5
  require 'aspera/cli/plugins/config'
@@ -19,30 +20,34 @@ module Aspera
19
20
  module Plugins
20
21
  class Faspex < BasicAuthPlugin
21
22
  # required hash key for source in config
22
- KEY_NODE='node' # value must be hash with url, username, password
23
- KEY_PATH='path' # value must be same sub-path as in Faspex's node
24
- VAL_ALL='ALL'
23
+ KEY_NODE = 'node' # value must be hash with url, username, password
24
+ KEY_PATH = 'path' # value must be same sub-path as in Faspex's node
25
+ VAL_ALL = 'ALL'
25
26
  # added field in result that identifies the package
26
- PACKAGE_MATCH_FIELD='package_id'
27
+ PACKAGE_MATCH_FIELD = 'package_id'
27
28
  # list of supported atoms
28
- ATOM_MAILBOXES=[:inbox, :archive, :sent]
29
+ ATOM_MAILBOXES = %i[inbox archive sent].freeze
29
30
  # allowed parameters for inbox.atom
30
- ATOM_PARAMS=['page', 'count', 'startIndex']
31
+ ATOM_PARAMS = %w[page count startIndex].freeze
31
32
  # with special parameters (from Plugin class) : max and pmax
32
- ATOM_EXT_PARAMS=ATOM_PARAMS+[MAX_ITEMS, MAX_PAGES]
33
+ ATOM_EXT_PARAMS = ATOM_PARAMS + [MAX_ITEMS, MAX_PAGES]
33
34
  # sub path in url for public link delivery
34
- PUB_LINK_EXTERNAL_MATCH='external_deliveries/'
35
- private_constant :KEY_NODE,:KEY_PATH,:VAL_ALL,:PACKAGE_MATCH_FIELD,:ATOM_MAILBOXES,
36
- :ATOM_PARAMS,:ATOM_EXT_PARAMS,:PUB_LINK_EXTERNAL_MATCH
35
+ PUB_LINK_EXTERNAL_MATCH = 'external_deliveries/'
36
+ private_constant :KEY_NODE,:KEY_PATH,:VAL_ALL,:PACKAGE_MATCH_FIELD,:ATOM_MAILBOXES,:ATOM_PARAMS,
37
+ :ATOM_EXT_PARAMS,:PUB_LINK_EXTERNAL_MATCH
37
38
 
38
39
  class << self
39
40
  def detect(base_url)
40
- api=Rest.new({base_url: base_url})
41
- result=api.call({operation: 'POST',subpath: 'aspera/faspex',headers: {'Accept'=>'application/xrds+xml'},text_body_params: ''})
41
+ api = Rest.new(base_url: base_url)
42
+ result = api.call(
43
+ operation: 'POST',
44
+ subpath: 'aspera/faspex',
45
+ headers: {'Accept' => 'application/xrds+xml', 'Content-type' => 'text/plain'},
46
+ text_body_params: '')
42
47
  # 4.x
43
48
  if result[:http].body.start_with?('<?xml')
44
- res_s=XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
45
- version=res_s['XRD']['application']['version']
49
+ res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
50
+ version = res_s['XRD']['application']['version']
46
51
  return {version: version}
47
52
  end
48
53
  return nil
@@ -50,15 +55,15 @@ module Aspera
50
55
 
51
56
  # extract elements from anonymous faspex link
52
57
  def get_link_data(publink)
53
- publink_uri=URI.parse(publink)
54
- raise CliBadArgument, 'public link does not match Faspex format' unless (m=publink_uri.path.match(/^(.*)\/(external.*)$/))
55
- base=m[1]
56
- subpath=m[2]
57
- port_add=publink_uri.port.eql?(publink_uri.default_port) ? '' : ":#{publink_uri.port}"
58
- result={
59
- base_url: "#{publink_uri.scheme}://#{publink_uri.host}#{port_add}#{base}",
60
- subpath: subpath,
61
- query: URI.decode_www_form(publink_uri.query).each_with_object({}){|v,h|h[v.first]=v.last;}
58
+ publink_uri = URI.parse(publink)
59
+ raise CliBadArgument, 'public link does not match Faspex format' unless (m = publink_uri.path.match(/^(.*)\/(external.*)$/))
60
+ base = m[1]
61
+ subpath = m[2]
62
+ port_add = publink_uri.port.eql?(publink_uri.default_port) ? '' : ":#{publink_uri.port}"
63
+ result = {
64
+ base_url: "#{publink_uri.scheme}://#{publink_uri.host}#{port_add}#{base}",
65
+ subpath: subpath,
66
+ query: URI.decode_www_form(publink_uri.query).each_with_object({}){|v,h|h[v.first] = v.last;}
62
67
  }
63
68
  Log.dump('publink',result)
64
69
  return result
@@ -70,7 +75,7 @@ module Aspera
70
75
  raise CliBadArgument, 'package has no link (deleted?)' if raise_no_link
71
76
  return nil
72
77
  end
73
- result=entry['link'].select{|e| e['rel'].eql?('package')}.first['href']
78
+ result = entry['link'].find{|e| e['rel'].eql?('package')}['href']
74
79
  # tags in the end of URL is not well % encoded... there are "=" that should be %3D
75
80
  # TODO: enter ticket to Faspex ?
76
81
  ###XXif m=result.match(/(=+)$/);result.gsub!(/=+$/,"#{"%3D"*m[1].length}");end
@@ -79,7 +84,7 @@ module Aspera
79
84
 
80
85
  def textify_package_list(table_data)
81
86
  return table_data.map do |e|
82
- e.keys.each {|k| e[k]=e[k].first if e[k].is_a?(Array) && (e[k].length == 1)}
87
+ e.keys.each {|k| e[k] = e[k].first if e[k].is_a?(Array) && (e[k].length == 1)}
83
88
  e['items'] = e.has_key?('link') ? e['link'].length : 0
84
89
  e
85
90
  end
@@ -87,7 +92,7 @@ module Aspera
87
92
 
88
93
  # field_sym : :id or :name
89
94
  def get_source_id(source_list,source_name)
90
- source_ids=source_list.select { |i| i['name'].eql?(source_name) }
95
+ source_ids = source_list.select { |i| i['name'].eql?(source_name) }
91
96
  if source_ids.empty?
92
97
  raise CliError,%Q(No such Faspex source "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
93
98
  end
@@ -96,8 +101,8 @@ module Aspera
96
101
  end
97
102
 
98
103
  def initialize(env)
99
- @api_v3=nil
100
- @api_v4=nil
104
+ @api_v3 = nil
105
+ @api_v4 = nil
101
106
  super(env)
102
107
  options.add_opt_simple(:link,'public link for specific operation')
103
108
  options.add_opt_simple(:delivery_info,'package delivery information (extended value)')
@@ -111,23 +116,23 @@ module Aspera
111
116
 
112
117
  def api_v3
113
118
  if @api_v3.nil?
114
- @api_v3=basic_auth_api
119
+ @api_v3 = basic_auth_api
115
120
  end
116
121
  return @api_v3
117
122
  end
118
123
 
119
124
  def api_v4
120
125
  if @api_v4.nil?
121
- faspex_api_base=options.get_option(:url,:mandatory)
122
- @api_v4=Rest.new({
123
- base_url: faspex_api_base+'/api',
124
- auth: {
125
- type: :oauth2,
126
- base_url: faspex_api_base+'/auth/oauth2',
127
- auth: {type: :basic, username: options.get_option(:username,:mandatory), password: options.get_option(:password,:mandatory)},
128
- crtype: :generic,
129
- generic: {grant_type: 'password'},
130
- scope: 'admin'
126
+ faspex_api_base = options.get_option(:url,is_type: :mandatory)
127
+ @api_v4 = Rest.new({
128
+ base_url: faspex_api_base + '/api',
129
+ auth: {
130
+ type: :oauth2,
131
+ base_url: faspex_api_base + '/auth/oauth2',
132
+ auth: {type: :basic, username: options.get_option(:username,is_type: :mandatory), password: options.get_option(:password,is_type: :mandatory)},
133
+ crtype: :generic,
134
+ generic: {grant_type: 'password'},
135
+ scope: 'admin'
131
136
  }})
132
137
  end
133
138
  return @api_v4
@@ -135,48 +140,48 @@ module Aspera
135
140
 
136
141
  # query supports : {"startIndex":10,"count":1,"page":109,"max":2,"pmax":1}
137
142
  def mailbox_filtered_entries(stop_at_id: nil)
138
- recipient_names=[options.get_option(:recipient,:optional) || options.get_option(:username,:mandatory)]
143
+ recipient_names = [options.get_option(:recipient) || options.get_option(:username,is_type: :mandatory)]
139
144
  # some workgroup messages have no star in recipient name
140
145
  recipient_names.push(recipient_names.first[1..-1]) if recipient_names.first.start_with?('*')
141
146
  # mailbox is in ATOM_MAILBOXES
142
- mailbox=options.get_option(:box,:mandatory)
147
+ mailbox = options.get_option(:box,is_type: :mandatory)
143
148
  # parameters
144
- mailbox_query=options.get_option(:query,:optional)
145
- max_items=nil
146
- max_pages=nil
147
- result=[]
149
+ mailbox_query = options.get_option(:query)
150
+ max_items = nil
151
+ max_pages = nil
152
+ result = []
148
153
  if !mailbox_query.nil?
149
154
  raise 'query: must be Hash or nil' unless mailbox_query.is_a?(Hash)
150
- raise "query: supported params: #{ATOM_EXT_PARAMS}" unless (mailbox_query.keys-ATOM_EXT_PARAMS).empty?
155
+ raise "query: supported params: #{ATOM_EXT_PARAMS}" unless (mailbox_query.keys - ATOM_EXT_PARAMS).empty?
151
156
  raise 'query: startIndex and page are exclusive' if mailbox_query.has_key?('startIndex') && mailbox_query.has_key?('page')
152
- max_items=mailbox_query[MAX_ITEMS]
157
+ max_items = mailbox_query[MAX_ITEMS]
153
158
  mailbox_query.delete(MAX_ITEMS)
154
- max_pages=mailbox_query[MAX_PAGES]
159
+ max_pages = mailbox_query[MAX_PAGES]
155
160
  mailbox_query.delete(MAX_PAGES)
156
161
  end
157
162
  loop do
158
163
  # get a batch of package information
159
164
  # order: first batch is latest packages, and then in a batch ids are increasing
160
- atom_xml=api_v3.call({operation: 'GET',subpath: "#{mailbox}.atom",headers: {'Accept'=>'application/xml'},url_params: mailbox_query})[:http].body
161
- box_data=XmlSimple.xml_in(atom_xml, {'ForceArray' => true})
165
+ atom_xml = api_v3.call({operation: 'GET',subpath: "#{mailbox}.atom",headers: {'Accept' => 'application/xml'},url_params: mailbox_query})[:http].body
166
+ box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => true})
162
167
  Log.dump(:box_data,box_data)
163
- items=box_data.has_key?('entry') ? box_data['entry'] : []
168
+ items = box_data.has_key?('entry') ? box_data['entry'] : []
164
169
  Log.log.debug("new items: #{items.count}")
165
170
  # it is the end if page is empty
166
171
  break if items.empty?
167
- stop_condition=false
172
+ stop_condition = false
168
173
  # results will be sorted in reverse id
169
- items.reverse.each do |package|
170
- package[PACKAGE_MATCH_FIELD]=
171
- case mailbox
172
- when :inbox,:archive
173
- recipient=package['to'].select{|i|recipient_names.include?(i['name'].first)}.first
174
- recipient.nil? ? nil : recipient['recipient_delivery_id'].first
175
- else # :sent
176
- package['delivery_id'].first
177
- end
174
+ items.reverse_each do |package|
175
+ package[PACKAGE_MATCH_FIELD] =
176
+ case mailbox
177
+ when :inbox,:archive
178
+ recipient = package['to'].find{|i|recipient_names.include?(i['name'].first)}
179
+ recipient.nil? ? nil : recipient['recipient_delivery_id'].first
180
+ else # :sent
181
+ package['delivery_id'].first
182
+ end
178
183
  # if we look for a specific package
179
- stop_condition=true if !stop_at_id.nil? && stop_at_id.eql?(package[PACKAGE_MATCH_FIELD])
184
+ stop_condition = true if !stop_at_id.nil? && stop_at_id.eql?(package[PACKAGE_MATCH_FIELD])
180
185
  # keep only those for the specified recipient,
181
186
  result.push(package) unless package[PACKAGE_MATCH_FIELD].nil?
182
187
  end
@@ -185,16 +190,16 @@ module Aspera
185
190
  Log.log.debug("total items: #{result.count}")
186
191
  # reach the limit ?
187
192
  if !max_items.nil? && (result.count >= max_items)
188
- result=result.slice(0,max_items) if result.count > max_items
193
+ result = result.slice(0,max_items) if result.count > max_items
189
194
  break
190
195
  end
191
- link=box_data['link'].select{|i|i['rel'].eql?('next')}.first
196
+ link = box_data['link'].find{|i|i['rel'].eql?('next')}
192
197
  Log.log.debug("link: #{link}")
193
198
  # no next link
194
199
  break if link.nil?
195
200
  # replace parameters with the ones from next link
196
- params=CGI.parse(URI.parse(link['href']).query)
197
- mailbox_query=params.keys.each_with_object({}){|i,m|;m[i]=params[i].first;}
201
+ params = CGI.parse(URI.parse(link['href']).query)
202
+ mailbox_query = params.keys.each_with_object({}){|i,m|;m[i] = params[i].first;}
198
203
  Log.log.debug("query: #{mailbox_query}")
199
204
  break if !max_pages.nil? && (mailbox_query['page'].to_i > max_pages)
200
205
  end
@@ -203,43 +208,46 @@ module Aspera
203
208
 
204
209
  # retrieve transfer spec from pub link for send package
205
210
  def send_publink_to_ts(public_link_url,package_create_params)
206
- delivery_info=package_create_params['delivery']
211
+ delivery_info = package_create_params['delivery']
207
212
  # pub link user
208
- link_data=self.class.get_link_data(public_link_url)
213
+ link_data = self.class.get_link_data(public_link_url)
209
214
  if !['external/submissions/new','external/dropbox_submissions/new'].include?(link_data[:subpath])
210
215
  raise CliBadArgument,"pub link is #{link_data[:subpath]}, expecting external/submissions/new"
211
216
  end
212
- create_path=link_data[:subpath].split('/')[0..-2].join('/')
213
- package_create_params.merge!({passcode: link_data[:query]['passcode']})
214
- delivery_info.merge!({
215
- transfer_type: 'connect',
216
- source_paths_list: transfer.ts_source_paths.map{|i|i['source']}.join("\r\n")})
217
- api_public_link=Rest.new({base_url: link_data[:base_url]})
217
+ create_path = link_data[:subpath].split('/')[0..-2].join('/')
218
+ package_create_params[:passcode] = link_data[:query]['passcode']
219
+ delivery_info[:transfer_type] = 'connect'
220
+ delivery_info[:source_paths_list] = transfer.ts_source_paths.map{|i|i['source']}.join("\r\n")
221
+ api_public_link = Rest.new({base_url: link_data[:base_url]})
218
222
  # Hum, as this does not always work (only user, but not dropbox), we get the javascript and need hack
219
223
  #pkg_created=api_public_link.create(create_path,package_create_params)[:data]
220
224
  # so extract data from javascript
221
- pkgdatares=api_public_link.call({operation: 'POST',subpath: create_path,json_params: package_create_params,headers: {'Accept'=>'text/javascript'}})[:http].body
225
+ pkgdatares = api_public_link.call({
226
+ operation: 'POST',
227
+ subpath: create_path,
228
+ json_params: package_create_params,
229
+ headers: {'Accept' => 'text/javascript'}})[:http].body
222
230
  # get args of function call
223
- pkgdatares.gsub!("\n",'') # one line
231
+ pkgdatares.delete!("\n") # one line
224
232
  pkgdatares.gsub!(/^[^"]+\("\{/,'{') # delete header
225
233
  pkgdatares.gsub!(/"\);[^"]+$/,'"') # delete trailer
226
234
  pkgdatares.gsub!(/\}", *"/,'},"') # between two args
227
235
  pkgdatares.gsub!('\\"','"') # remove protecting quote
228
236
  begin
229
- pkgdatares=JSON.parse("[#{pkgdatares}]")
237
+ pkgdatares = JSON.parse("[#{pkgdatares}]")
230
238
  rescue JSON::ParserError # => e
231
239
  raise 'Link not valid'
232
240
  end
233
241
  return pkgdatares.first
234
242
  end
235
243
 
236
- ACTIONS=[:health,:package, :source, :me, :dropbox, :v4, :address_book, :login_methods].freeze
244
+ ACTIONS = %i[health package source me dropbox v4 address_book login_methods].freeze
237
245
 
238
246
  def execute_action
239
- command=options.get_next_command(ACTIONS)
247
+ command = options.get_next_command(ACTIONS)
240
248
  case command
241
249
  when :health
242
- nagios=Nagios.new
250
+ nagios = Nagios.new
243
251
  begin
244
252
  api_v3.read('me')
245
253
  nagios.add_ok('faspex api','accessible')
@@ -248,143 +256,163 @@ module Aspera
248
256
  end
249
257
  return nagios.result
250
258
  when :package
251
- command_pkg=options.get_next_command([:send, :recv, :list])
259
+ command_pkg = options.get_next_command(%i[send recv list])
252
260
  case command_pkg
253
261
  when :list
254
- return {type: :object_list,data: mailbox_filtered_entries,fields: [PACKAGE_MATCH_FIELD,'title','items'], textify: lambda {|table_data|Faspex.textify_package_list(table_data)} }
262
+ return {
263
+ type: :object_list,
264
+ data: mailbox_filtered_entries,
265
+ fields: [PACKAGE_MATCH_FIELD,'title','items'],
266
+ textify: lambda {|table_data|Faspex.textify_package_list(table_data)}
267
+ }
255
268
  when :send
256
- delivery_info=options.get_option(:delivery_info,:mandatory)
269
+ delivery_info = options.get_option(:delivery_info,is_type: :mandatory)
257
270
  raise CliBadArgument,'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
258
271
  # actual parameter to faspex API
259
- package_create_params={'delivery'=>delivery_info}
260
- public_link_url=options.get_option(:link,:optional)
272
+ package_create_params = {'delivery' => delivery_info}
273
+ public_link_url = options.get_option(:link)
261
274
  if public_link_url.nil?
262
275
  # authenticated user
263
- delivery_info['sources']||=[{'paths'=>[]}]
264
- first_source=delivery_info['sources'].first
276
+ delivery_info['sources'] ||= [{'paths' => []}]
277
+ first_source = delivery_info['sources'].first
265
278
  first_source['paths'].push(*transfer.ts_source_paths.map{|i|i['source']})
266
- source_name=options.get_option(:source_name,:optional)
279
+ source_name = options.get_option(:source_name)
267
280
  if !source_name.nil?
268
- source_list=api_v3.call({operation: 'GET',subpath: 'source_shares',headers: {'Accept'=>'application/json'}})[:data]['items']
269
- source_id=self.class.get_source_id(source_list,source_name)
270
- first_source['id']=source_id
281
+ source_list = api_v3.call({operation: 'GET',subpath: 'source_shares',headers: {'Accept' => 'application/json'}})[:data]['items']
282
+ source_id = self.class.get_source_id(source_list,source_name)
283
+ first_source['id'] = source_id
271
284
  end
272
- pkg_created=api_v3.call({operation: 'POST',subpath: 'send',json_params: package_create_params,headers: {'Accept'=>'application/json'}})[:data]
285
+ pkg_created = api_v3.call({
286
+ operation: 'POST',
287
+ subpath: 'send',
288
+ json_params: package_create_params,
289
+ headers: {'Accept' => 'application/json'}
290
+ })[:data]
273
291
  if !source_name.nil?
274
292
  # no transfer spec if remote source
275
293
  return {data: [pkg_created['links']['status']],type: :value_list,name: 'link'}
276
294
  end
277
295
  raise CliBadArgument,'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
278
- transfer_spec=pkg_created['xfer_sessions'].first
296
+ transfer_spec = pkg_created['xfer_sessions'].first
279
297
  # use source from cmd line, this one only contains destination (already in dest root)
280
298
  transfer_spec.delete('paths')
281
299
  else # publink
282
- transfer_spec=send_publink_to_ts(public_link_url,package_create_params)
300
+ transfer_spec = send_publink_to_ts(public_link_url,package_create_params)
283
301
  end
284
302
  #Log.dump('transfer_spec',transfer_spec)
285
303
  return Main.result_transfer(transfer.start(transfer_spec,{src: :node_gen3}))
286
304
  when :recv
287
- link_url=options.get_option(:link,:optional)
305
+ link_url = options.get_option(:link)
288
306
  # list of faspex ID/URI to download
289
- pkg_id_uri=nil
290
- skip_ids_data=[]
291
- skip_ids_persistency=nil
307
+ pkg_id_uri = nil
308
+ skip_ids_data = []
309
+ skip_ids_persistency = nil
292
310
  case link_url
293
311
  when nil # usual case: no link
294
- if options.get_option(:once_only,:mandatory)
295
- skip_ids_persistency=PersistencyActionOnce.new(
296
- manager: @agents[:persistency],
297
- data: skip_ids_data,
298
- id: IdGenerator.from_list(['faspex_recv',options.get_option(:url,:mandatory),options.get_option(:username,:mandatory),options.get_option(:box,:mandatory).to_s]))
312
+ if options.get_option(:once_only,is_type: :mandatory)
313
+ skip_ids_persistency = PersistencyActionOnce.new(
314
+ manager: @agents[:persistency],
315
+ data: skip_ids_data,
316
+ id: IdGenerator.from_list([
317
+ 'faspex_recv',
318
+ options.get_option(:url,is_type: :mandatory),
319
+ options.get_option(:username,is_type: :mandatory),
320
+ options.get_option(:box,is_type: :mandatory).to_s
321
+ ]))
299
322
  end
300
323
  # get command line parameters
301
- delivid=instance_identifier()
324
+ delivid = instance_identifier
302
325
  raise 'empty id' if delivid.empty?
303
- recipient=options.get_option(:recipient,:optional)
326
+ recipient = options.get_option(:recipient)
304
327
  if delivid.eql?(VAL_ALL)
305
- pkg_id_uri=mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD],uri: self.class.get_fasp_uri_from_entry(i, raise_no_link: false)}}
328
+ pkg_id_uri = mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD],uri: self.class.get_fasp_uri_from_entry(i, raise_no_link: false)}}
306
329
  # TODO : remove ids from skip not present in inbox to avoid growing too big
307
330
  # skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
308
331
  pkg_id_uri.reject!{|i|skip_ids_data.include?(i[:id])}
309
332
  elsif !recipient.nil? && recipient.start_with?('*')
310
- found_package_link=mailbox_filtered_entries(stop_at_id: delivid).select{|p|p[PACKAGE_MATCH_FIELD].eql?(delivid)}.first['link'].first['href']
333
+ found_package_link = mailbox_filtered_entries(stop_at_id: delivid).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivid)}['link'].first['href']
311
334
  raise 'Not Found. Dropbox and Workgroup packages can use the link option with faspe:' if found_package_link.nil?
312
- pkg_id_uri=[{id: delivid,uri: found_package_link}]
335
+ pkg_id_uri = [{id: delivid,uri: found_package_link}]
313
336
  else
314
337
  # TODO: delivery id is the right one if package was receive by workgroup
315
- endpoint=
316
- case options.get_option(:box,:mandatory)
317
- when :inbox,:archive then'received'
318
- when :sent then 'sent'
319
- end
320
- entry_xml=api_v3.call({operation: 'GET',subpath: "#{endpoint}/#{delivid}",headers: {'Accept'=>'application/xml'}})[:http].body
321
- package_entry=XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
322
- pkg_id_uri=[{id: delivid,uri: self.class.get_fasp_uri_from_entry(package_entry)}]
338
+ endpoint =
339
+ case options.get_option(:box,is_type: :mandatory)
340
+ when :inbox,:archive then'received'
341
+ when :sent then 'sent'
342
+ end
343
+ entry_xml = api_v3.call({operation: 'GET',subpath: "#{endpoint}/#{delivid}",headers: {'Accept' => 'application/xml'}})[:http].body
344
+ package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
345
+ pkg_id_uri = [{id: delivid,uri: self.class.get_fasp_uri_from_entry(package_entry)}]
323
346
  end
324
347
  when /^faspe:/
325
- pkg_id_uri=[{id: 'package',uri: link_url}]
348
+ pkg_id_uri = [{id: 'package',uri: link_url}]
326
349
  else
327
- link_data=self.class.get_link_data(link_url)
350
+ link_data = self.class.get_link_data(link_url)
328
351
  if !link_data[:subpath].start_with?(PUB_LINK_EXTERNAL_MATCH)
329
352
  raise CliBadArgument,"Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
330
353
  end
331
354
  # Note: unauthenticated API (authorization is in url params)
332
- api_public_link=Rest.new({base_url: link_data[:base_url]})
333
- pkgdatares=api_public_link.call({operation: 'GET',subpath: link_data[:subpath],url_params: {passcode: link_data[:query]['passcode']}, headers: {'Accept'=>'application/xml'}})
355
+ api_public_link = Rest.new({base_url: link_data[:base_url]})
356
+ pkgdatares = api_public_link.call(
357
+ operation: 'GET',
358
+ subpath: link_data[:subpath],
359
+ url_params: {passcode: link_data[:query]['passcode']},
360
+ headers: {'Accept' => 'application/xml'})
334
361
  if !pkgdatares[:http].body.start_with?('<?xml ')
335
362
  OpenApplication.instance.uri(link_url)
336
363
  raise CliError, 'no such package'
337
364
  end
338
- package_entry=XmlSimple.xml_in(pkgdatares[:http].body, {'ForceArray' => false})
365
+ package_entry = XmlSimple.xml_in(pkgdatares[:http].body, {'ForceArray' => false})
339
366
  Log.dump(:package_entry,package_entry)
340
- transfer_uri=self.class.get_fasp_uri_from_entry(package_entry)
341
- pkg_id_uri=[{id: package_entry['id'],uri: transfer_uri}]
367
+ transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
368
+ pkg_id_uri = [{id: package_entry['id'],uri: transfer_uri}]
342
369
  end # public link
343
370
  Log.dump(:pkg_id_uri,pkg_id_uri)
344
371
  return Main.result_status('no package') if pkg_id_uri.empty?
345
- result_transfer=[]
372
+ result_transfer = []
346
373
  pkg_id_uri.each do |id_uri|
347
374
  if id_uri[:uri].nil?
348
375
  # skip package with no link: empty or content deleted
349
- statuses=[:success]
376
+ statuses = [:success]
350
377
  else
351
- transfer_spec=Fasp::Uri.new(id_uri[:uri]).transfer_spec
378
+ transfer_spec = Fasp::Uri.new(id_uri[:uri]).transfer_spec
352
379
  # NOTE: only external users have token in faspe: link !
353
380
  if !transfer_spec.has_key?('token')
354
- sanitized=id_uri[:uri].gsub('&','&amp;')
355
- xmlpayload=%Q(<?xml version="1.0" encoding="UTF-8"?><url-list xmlns="http://schemas.asperasoft.com/xml/url-list"><url href="#{sanitized}"/></url-list>)
356
- transfer_spec['token']=api_v3.call({
357
- operation: 'POST',
358
- subpath: 'issue-token?direction=down',
359
- headers: {'Accept'=>'text/plain','Content-Type'=>'application/vnd.aspera.url-list+xml'},
381
+ sanitized = id_uri[:uri].gsub('&','&amp;')
382
+ xmlpayload =
383
+ %Q(<?xml version="1.0" encoding="UTF-8"?><url-list xmlns="http://schemas.asperasoft.com/xml/url-list"><url href="#{sanitized}"/></url-list>)
384
+ transfer_spec['token'] = api_v3.call({
385
+ operation: 'POST',
386
+ subpath: 'issue-token?direction=down',
387
+ headers: {'Accept' => 'text/plain','Content-Type' => 'application/vnd.aspera.url-list+xml'},
360
388
  text_body_params: xmlpayload})[:http].body
361
389
  end
362
- transfer_spec['direction']=Fasp::TransferSpec::DIRECTION_RECEIVE
363
- statuses=transfer.start(transfer_spec,{src: :node_gen3})
390
+ transfer_spec['direction'] = Fasp::TransferSpec::DIRECTION_RECEIVE
391
+ statuses = transfer.start(transfer_spec,{src: :node_gen3})
364
392
  end
365
- result_transfer.push({'package'=>id_uri[:id],Main::STATUS_FIELD=>statuses})
393
+ result_transfer.push({'package' => id_uri[:id],Main::STATUS_FIELD => statuses})
366
394
  # skip only if all sessions completed
367
395
  skip_ids_data.push(id_uri[:id]) if TransferAgent.session_status(statuses).eql?(:success)
368
396
  end
369
- skip_ids_persistency.save unless skip_ids_persistency.nil?
397
+ skip_ids_persistency&.save
370
398
  return Main.result_transfer_multiple(result_transfer)
371
399
  end
372
400
  when :source
373
- command_source=options.get_next_command([:list, :id, :name])
374
- source_list=api_v3.call({operation: 'GET',subpath: 'source_shares',headers: {'Accept'=>'application/json'}})[:data]['items']
401
+ command_source = options.get_next_command(%i[list id name])
402
+ source_list = api_v3.call({operation: 'GET',subpath: 'source_shares',headers: {'Accept' => 'application/json'}})[:data]['items']
375
403
  case command_source
376
404
  when :list
377
405
  return {type: :object_list,data: source_list}
378
406
  else # :id or :name
379
- source_match_val=options.get_next_argument('source id or name')
380
- source_ids=source_list.select { |i| i[command_source.to_s].to_s.eql?(source_match_val) }
407
+ source_match_val = options.get_next_argument('source id or name')
408
+ source_ids = source_list.select { |i| i[command_source.to_s].to_s.eql?(source_match_val) }
381
409
  if source_ids.empty?
382
410
  raise CliError,"No such Faspex source #{command_source}: #{source_match_val} in [#{source_list.map{|i| i[command_source.to_s]}.join(', ')}]"
383
411
  end
384
412
  # get id and name
385
- source_name=source_ids.first['name']
413
+ source_name = source_ids.first['name']
386
414
  #source_id=source_ids.first['id']
387
- source_hash=options.get_option(:storage,:mandatory)
415
+ source_hash = options.get_option(:storage,is_type: :mandatory)
388
416
  # check value of option
389
417
  raise CliError,'storage option must be a Hash' unless source_hash.is_a?(Hash)
390
418
  source_hash.each do |name,storage|
@@ -396,64 +424,69 @@ module Aspera
396
424
  if !source_hash.has_key?(source_name)
397
425
  raise CliError,"No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
398
426
  end
399
- source_info=source_hash[source_name]
427
+ source_info = source_hash[source_name]
400
428
  Log.log.debug("source_info: #{source_info}")
401
- command_node=options.get_next_command([:info, :node])
429
+ command_node = options.get_next_command(%i[info node])
402
430
  case command_node
403
431
  when :info
404
432
  return {data: source_info,type: :single_object}
405
433
  when :node
406
- node_config=ExtendedValue.instance.evaluate(source_info[KEY_NODE])
434
+ node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
407
435
  raise CliError,"bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
408
436
  Log.log.debug("node=#{node_config}")
409
- api_node=Rest.new({
410
- base_url: node_config['url'],
411
- auth: {
412
- type: :basic,
413
- username: node_config['username'],
414
- password: node_config['password']}})
415
- command=options.get_next_command(Node::COMMON_ACTIONS)
437
+ api_node = Rest.new({
438
+ base_url: node_config['url'],
439
+ auth: {
440
+ type: :basic,
441
+ username: node_config['username'],
442
+ password: node_config['password']}})
443
+ command = options.get_next_command(Node::COMMON_ACTIONS)
416
444
  return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command,source_info[KEY_PATH])
417
445
  end
418
446
  end
419
447
  when :me
420
- my_info=api_v3.call({operation: 'GET',subpath: 'me',headers: {'Accept'=>'application/json'}})[:data]
448
+ my_info = api_v3.call({operation: 'GET',subpath: 'me',headers: {'Accept' => 'application/json'}})[:data]
421
449
  return {data: my_info, type: :single_object}
422
450
  when :dropbox
423
- command_pkg=options.get_next_command([:list])
451
+ command_pkg = options.get_next_command([:list])
424
452
  case command_pkg
425
453
  when :list
426
- dropbox_list=api_v3.call({operation: 'GET',subpath: 'dropboxes',headers: {'Accept'=>'application/json'}})[:data]
427
- return {type: :object_list, data: dropbox_list['items'], fields: ['name','id','description','can_read','can_write']}
454
+ dropbox_list = api_v3.call({operation: 'GET',subpath: 'dropboxes',headers: {'Accept' => 'application/json'}})[:data]
455
+ return {type: :object_list, data: dropbox_list['items'], fields: %w[name id description can_read can_write]}
428
456
  end
429
457
  when :v4
430
- command=options.get_next_command([:package,:dropbox, :dmembership, :workgroup,:wmembership,:user,:metadata_profile])
458
+ command = options.get_next_command(%i[package dropbox dmembership workgroup wmembership user metadata_profile])
431
459
  case command
432
460
  when :dropbox
433
- return entity_action(api_v4,'admin/dropboxes',display_fields: ['id','e_wg_name','e_wg_desc','created_at'])
461
+ return entity_action(api_v4,'admin/dropboxes',display_fields: %w[id e_wg_name e_wg_desc created_at])
434
462
  when :dmembership
435
463
  return entity_action(api_v4,'dropbox_memberships')
436
464
  when :workgroup
437
- return entity_action(api_v4,'admin/workgroups',display_fields: ['id','e_wg_name','e_wg_desc','created_at'])
465
+ return entity_action(api_v4,'admin/workgroups',display_fields: %w[id e_wg_name e_wg_desc created_at])
438
466
  when :wmembership
439
467
  return entity_action(api_v4,'workgroup_memberships')
440
468
  when :user
441
- return entity_action(api_v4,'users',display_fields: ['id','name','first_name','last_name'])
469
+ return entity_action(api_v4,'users',display_fields: %w[id name first_name last_name])
442
470
  when :metadata_profile
443
471
  return entity_action(api_v4,'metadata_profiles')
444
472
  when :package
445
- pkg_box_type=options.get_next_command([:users])
446
- pkg_box_id=instance_identifier()
473
+ pkg_box_type = options.get_next_command([:users])
474
+ pkg_box_id = instance_identifier
447
475
  return entity_action(api_v4,"#{pkg_box_type}/#{pkg_box_id}/packages")
448
476
  end
449
477
  when :address_book
450
- result=api_v3.call({operation: 'GET',subpath: 'address-book',headers: {'Accept'=>'application/json'},url_params: {'format'=>'json','count'=>100_000}})[:data]
478
+ result = api_v3.call(
479
+ operation: 'GET',
480
+ subpath: 'address-book',
481
+ headers: {'Accept' => 'application/json'},
482
+ url_params: {'format' => 'json','count' => 100_000}
483
+ )[:data]
451
484
  self.format.display_status("users: #{result['itemsPerPage']}/#{result['totalResults']}, start:#{result['startIndex']}")
452
- users=result['entry']
485
+ users = result['entry']
453
486
  # add missing entries
454
487
  users.each do |u|
455
488
  unless u['emails'].nil?
456
- email=u['emails'].find{|i|i['primary'].eql?('true')}
489
+ email = u['emails'].find{|i|i['primary'].eql?('true')}
457
490
  u['email'] = email['value'] unless email.nil?
458
491
  end
459
492
  if u['email'].nil?
@@ -461,12 +494,12 @@ module Aspera
461
494
  next
462
495
  end
463
496
  u['first_name'],u['last_name'] = u['displayName'].split(' ',2)
464
- u['x']=true
497
+ u['x'] = true
465
498
  end
466
499
  return {type: :object_list,data: users}
467
500
  when :login_methods
468
- login_meths=api_v3.call({operation: 'GET',subpath: 'login/new',headers: {'Accept'=>'application/xrds+xml'}})[:http].body
469
- login_methods=XmlSimple.xml_in(login_meths, {'ForceArray' => false})
501
+ login_meths = api_v3.call({operation: 'GET',subpath: 'login/new',headers: {'Accept' => 'application/xrds+xml'}})[:http].body
502
+ login_methods = XmlSimple.xml_in(login_meths, {'ForceArray' => false})
470
503
  return {type: :object_list, data: login_methods['XRD']['Service']}
471
504
  end # command
472
505
  end