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