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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -0
- data/README.md +844 -861
- data/bin/ascli +20 -1
- data/bin/asession +37 -34
- data/docs/test_env.conf +11 -3
- data/examples/aoc.rb +13 -12
- data/examples/dascli +26 -0
- data/examples/faspex4.rb +34 -29
- data/examples/transfer.rb +30 -29
- data/lib/aspera/aoc.rb +151 -143
- data/lib/aspera/ascmd.rb +56 -45
- data/lib/aspera/ats_api.rb +6 -5
- data/lib/aspera/cli/basic_auth_plugin.rb +18 -16
- data/lib/aspera/cli/extended_value.rb +32 -30
- data/lib/aspera/cli/formater.rb +103 -111
- data/lib/aspera/cli/info.rb +2 -1
- data/lib/aspera/cli/listener/line_dump.rb +1 -0
- data/lib/aspera/cli/listener/logger.rb +1 -0
- data/lib/aspera/cli/listener/progress.rb +13 -12
- data/lib/aspera/cli/listener/progress_multi.rb +21 -20
- data/lib/aspera/cli/main.rb +106 -89
- data/lib/aspera/cli/manager.rb +96 -85
- data/lib/aspera/cli/plugin.rb +50 -32
- data/lib/aspera/cli/plugins/alee.rb +6 -5
- data/lib/aspera/cli/plugins/aoc.rb +521 -426
- data/lib/aspera/cli/plugins/ats.rb +84 -83
- data/lib/aspera/cli/plugins/bss.rb +30 -27
- data/lib/aspera/cli/plugins/config.rb +483 -397
- data/lib/aspera/cli/plugins/console.rb +17 -15
- data/lib/aspera/cli/plugins/cos.rb +26 -35
- data/lib/aspera/cli/plugins/faspex.rb +201 -168
- data/lib/aspera/cli/plugins/faspex5.rb +109 -74
- data/lib/aspera/cli/plugins/node.rb +378 -189
- data/lib/aspera/cli/plugins/orchestrator.rb +71 -65
- data/lib/aspera/cli/plugins/preview.rb +131 -122
- data/lib/aspera/cli/plugins/server.rb +94 -93
- data/lib/aspera/cli/plugins/shares.rb +42 -28
- data/lib/aspera/cli/plugins/sync.rb +15 -14
- data/lib/aspera/cli/transfer_agent.rb +56 -52
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/colors.rb +29 -28
- data/lib/aspera/command_line_builder.rb +50 -43
- data/lib/aspera/cos_node.rb +64 -38
- data/lib/aspera/data_repository.rb +1 -0
- data/lib/aspera/environment.rb +18 -8
- data/lib/aspera/fasp/agent_base.rb +26 -23
- data/lib/aspera/fasp/agent_connect.rb +35 -30
- data/lib/aspera/fasp/agent_direct.rb +68 -60
- data/lib/aspera/fasp/agent_httpgw.rb +71 -64
- data/lib/aspera/fasp/agent_node.rb +24 -23
- data/lib/aspera/fasp/agent_trsdk.rb +19 -20
- data/lib/aspera/fasp/error.rb +2 -1
- data/lib/aspera/fasp/error_info.rb +79 -68
- data/lib/aspera/fasp/installation.rb +122 -114
- data/lib/aspera/fasp/listener.rb +1 -0
- data/lib/aspera/fasp/parameters.rb +44 -41
- data/lib/aspera/fasp/resume_policy.rb +14 -11
- data/lib/aspera/fasp/transfer_spec.rb +6 -5
- data/lib/aspera/fasp/uri.rb +25 -24
- data/lib/aspera/faspex_gw.rb +83 -72
- data/lib/aspera/hash_ext.rb +10 -12
- data/lib/aspera/id_generator.rb +8 -7
- data/lib/aspera/keychain/encrypted_hash.rb +60 -45
- data/lib/aspera/keychain/macos_security.rb +26 -24
- data/lib/aspera/log.rb +34 -38
- data/lib/aspera/nagios.rb +14 -13
- data/lib/aspera/node.rb +19 -19
- data/lib/aspera/oauth.rb +121 -101
- data/lib/aspera/open_application.rb +6 -5
- data/lib/aspera/persistency_action_once.rb +9 -8
- data/lib/aspera/persistency_folder.rb +10 -9
- data/lib/aspera/preview/file_types.rb +261 -266
- data/lib/aspera/preview/generator.rb +74 -73
- data/lib/aspera/preview/image_error.png +0 -0
- data/lib/aspera/preview/options.rb +7 -6
- data/lib/aspera/preview/utils.rb +30 -33
- data/lib/aspera/preview/video_error.png +0 -0
- data/lib/aspera/proxy_auto_config.rb +25 -23
- data/lib/aspera/rest.rb +73 -74
- data/lib/aspera/rest_call_error.rb +1 -0
- data/lib/aspera/rest_error_analyzer.rb +11 -9
- data/lib/aspera/rest_errors_aspera.rb +5 -4
- data/lib/aspera/secret_hider.rb +68 -0
- data/lib/aspera/ssh.rb +12 -10
- data/lib/aspera/sync.rb +49 -47
- data/lib/aspera/temp_file_manager.rb +7 -5
- data/lib/aspera/timer_limiter.rb +9 -8
- data/lib/aspera/uri_reader.rb +11 -14
- data/lib/aspera/web_auth.rb +17 -15
- data.tar.gz.sig +0 -0
- metadata +117 -34
- metadata.gz.sig +2 -0
- 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=[
|
29
|
+
ATOM_MAILBOXES = %i[inbox archive sent].freeze
|
29
30
|
# allowed parameters for inbox.atom
|
30
|
-
ATOM_PARAMS=[
|
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
|
-
|
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(
|
41
|
-
result=api.call(
|
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:
|
60
|
-
subpath:
|
61
|
-
query:
|
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'].
|
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
|
122
|
-
@api_v4=Rest.new({
|
123
|
-
base_url:
|
124
|
-
auth:
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
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
|
147
|
+
mailbox = options.get_option(:box,is_type: :mandatory)
|
143
148
|
# parameters
|
144
|
-
mailbox_query=options.get_option(:query
|
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.
|
170
|
-
package[PACKAGE_MATCH_FIELD]=
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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'].
|
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
|
214
|
-
delivery_info
|
215
|
-
|
216
|
-
|
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({
|
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.
|
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=[
|
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([
|
259
|
+
command_pkg = options.get_next_command(%i[send recv list])
|
252
260
|
case command_pkg
|
253
261
|
when :list
|
254
|
-
return {
|
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
|
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
|
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
|
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({
|
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
|
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
|
295
|
-
skip_ids_persistency=PersistencyActionOnce.new(
|
296
|
-
|
297
|
-
|
298
|
-
|
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
|
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).
|
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
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
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(
|
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('&','&')
|
355
|
-
xmlpayload
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
381
|
+
sanitized = id_uri[:uri].gsub('&','&')
|
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
|
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([
|
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
|
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([
|
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:
|
411
|
-
auth:
|
412
|
-
|
413
|
-
|
414
|
-
|
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: [
|
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([
|
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: [
|
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: [
|
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: [
|
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(
|
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
|