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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +19 -0
  4. data/CHANGELOG.md +528 -0
  5. data/CONTRIBUTING.md +143 -0
  6. data/README.md +977 -589
  7. data/bin/ascli +4 -4
  8. data/bin/asession +12 -12
  9. data/docs/test_env.conf +29 -19
  10. data/examples/aoc.rb +6 -6
  11. data/examples/dascli +18 -16
  12. data/examples/faspex4.rb +15 -15
  13. data/examples/node.rb +12 -12
  14. data/examples/proxy.pac +2 -2
  15. data/examples/server.rb +12 -12
  16. data/lib/aspera/aoc.rb +344 -272
  17. data/lib/aspera/ascmd.rb +56 -54
  18. data/lib/aspera/ats_api.rb +4 -4
  19. data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
  20. data/lib/aspera/cli/extended_value.rb +9 -9
  21. data/lib/aspera/cli/{formater.rb → formatter.rb} +69 -69
  22. data/lib/aspera/cli/listener/line_dump.rb +1 -1
  23. data/lib/aspera/cli/listener/logger.rb +1 -1
  24. data/lib/aspera/cli/listener/progress.rb +5 -6
  25. data/lib/aspera/cli/listener/progress_multi.rb +16 -21
  26. data/lib/aspera/cli/main.rb +72 -73
  27. data/lib/aspera/cli/manager.rb +112 -112
  28. data/lib/aspera/cli/plugin.rb +68 -48
  29. data/lib/aspera/cli/plugins/alee.rb +4 -4
  30. data/lib/aspera/cli/plugins/aoc.rb +322 -720
  31. data/lib/aspera/cli/plugins/ats.rb +50 -52
  32. data/lib/aspera/cli/plugins/bss.rb +10 -10
  33. data/lib/aspera/cli/plugins/config.rb +514 -410
  34. data/lib/aspera/cli/plugins/console.rb +12 -12
  35. data/lib/aspera/cli/plugins/cos.rb +18 -20
  36. data/lib/aspera/cli/plugins/faspex.rb +134 -136
  37. data/lib/aspera/cli/plugins/faspex5.rb +235 -70
  38. data/lib/aspera/cli/plugins/node.rb +378 -309
  39. data/lib/aspera/cli/plugins/orchestrator.rb +52 -49
  40. data/lib/aspera/cli/plugins/preview.rb +129 -120
  41. data/lib/aspera/cli/plugins/server.rb +137 -83
  42. data/lib/aspera/cli/plugins/shares.rb +77 -52
  43. data/lib/aspera/cli/plugins/sync.rb +13 -33
  44. data/lib/aspera/cli/transfer_agent.rb +61 -61
  45. data/lib/aspera/cli/version.rb +2 -1
  46. data/lib/aspera/colors.rb +3 -3
  47. data/lib/aspera/command_line_builder.rb +78 -74
  48. data/lib/aspera/cos_node.rb +31 -29
  49. data/lib/aspera/data_repository.rb +1 -1
  50. data/lib/aspera/environment.rb +30 -28
  51. data/lib/aspera/fasp/agent_base.rb +17 -15
  52. data/lib/aspera/fasp/agent_connect.rb +34 -32
  53. data/lib/aspera/fasp/agent_direct.rb +70 -73
  54. data/lib/aspera/fasp/agent_httpgw.rb +79 -74
  55. data/lib/aspera/fasp/agent_node.rb +26 -26
  56. data/lib/aspera/fasp/agent_trsdk.rb +20 -20
  57. data/lib/aspera/fasp/error.rb +3 -2
  58. data/lib/aspera/fasp/error_info.rb +11 -8
  59. data/lib/aspera/fasp/installation.rb +80 -80
  60. data/lib/aspera/fasp/listener.rb +2 -2
  61. data/lib/aspera/fasp/parameters.rb +103 -92
  62. data/lib/aspera/fasp/parameters.yaml +313 -214
  63. data/lib/aspera/fasp/resume_policy.rb +10 -10
  64. data/lib/aspera/fasp/transfer_spec.rb +22 -2
  65. data/lib/aspera/fasp/uri.rb +7 -7
  66. data/lib/aspera/faspex_gw.rb +80 -159
  67. data/lib/aspera/faspex_postproc.rb +77 -0
  68. data/lib/aspera/hash_ext.rb +3 -3
  69. data/lib/aspera/id_generator.rb +5 -5
  70. data/lib/aspera/keychain/encrypted_hash.rb +23 -28
  71. data/lib/aspera/keychain/macos_security.rb +21 -20
  72. data/lib/aspera/log.rb +13 -13
  73. data/lib/aspera/nagios.rb +24 -23
  74. data/lib/aspera/node.rb +217 -38
  75. data/lib/aspera/oauth.rb +78 -74
  76. data/lib/aspera/open_application.rb +19 -11
  77. data/lib/aspera/persistency_action_once.rb +4 -4
  78. data/lib/aspera/persistency_folder.rb +13 -13
  79. data/lib/aspera/preview/file_types.rb +8 -8
  80. data/lib/aspera/preview/generator.rb +67 -67
  81. data/lib/aspera/preview/utils.rb +27 -27
  82. data/lib/aspera/proxy_auto_config.js +63 -63
  83. data/lib/aspera/proxy_auto_config.rb +19 -19
  84. data/lib/aspera/rest.rb +65 -67
  85. data/lib/aspera/rest_call_error.rb +2 -1
  86. data/lib/aspera/rest_error_analyzer.rb +22 -21
  87. data/lib/aspera/rest_errors_aspera.rb +16 -16
  88. data/lib/aspera/secret_hider.rb +17 -14
  89. data/lib/aspera/ssh.rb +15 -14
  90. data/lib/aspera/sync.rb +177 -62
  91. data/lib/aspera/temp_file_manager.rb +2 -2
  92. data/lib/aspera/uri_reader.rb +4 -4
  93. data/lib/aspera/web_auth.rb +13 -64
  94. data/lib/aspera/web_server_simple.rb +76 -0
  95. data.tar.gz.sig +0 -0
  96. metadata +11 -6
  97. metadata.gz.sig +0 -0
@@ -1,104 +1,170 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # spellchecker: ignore workgroups,mypackages
4
+
3
5
  require 'aspera/cli/basic_auth_plugin'
4
6
  require 'aspera/persistency_action_once'
5
7
  require 'aspera/id_generator'
6
8
  require 'aspera/nagios'
9
+ require 'aspera/environment'
7
10
  require 'securerandom'
11
+ require 'ruby-progressbar'
12
+ require 'tty-spinner'
8
13
 
9
14
  module Aspera
10
15
  module Cli
11
16
  module Plugins
12
- class Faspex5 < BasicAuthPlugin
17
+ class Faspex5 < Aspera::Cli::BasicAuthPlugin
18
+ RECIPIENT_TYPES = %w[user workgroup external_user distribution_list shared_inbox].freeze
19
+ PACKAGE_TERMINATED = %w[completed failed].freeze
20
+ API_DETECT = 'api/v5/configuration/ping'
13
21
  class << self
14
22
  def detect(base_url)
15
23
  api = Rest.new(base_url: base_url, redirect_max: 1)
16
- result = api.read('api/v5/configuration/ping')
24
+ result = api.read(API_DETECT)
17
25
  if result[:http].code.start_with?('2') && result[:http].body.strip.empty?
18
- return {version: '5'}
26
+ return {version: '5', url: result[:http].uri.to_s[0..-(API_DETECT.length + 2)]}
19
27
  end
20
28
  return nil
21
29
  end
22
30
  end
23
31
 
24
- VAL_ALL = 'ALL'
25
32
  TRANSFER_CONNECT = 'connect'
26
- private_constant :VAL_ALL,:TRANSFER_CONNECT
27
33
 
28
34
  def initialize(env)
29
35
  super(env)
30
- options.add_opt_simple(:client_id,'OAuth client identifier')
31
- options.add_opt_simple(:client_secret,'OAuth client secret')
32
- options.add_opt_simple(:redirect_uri,'OAuth redirect URI for web authentication')
33
- options.add_opt_list(:auth,[Oauth::STD_AUTH_TYPES,:boot].flatten,'OAuth type of authentication')
34
- options.add_opt_simple(:private_key,'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
35
- options.add_opt_simple(:passphrase,'RSA private key passphrase')
36
- options.set_option(:auth,:jwt)
36
+ options.add_opt_simple(:client_id, 'OAuth client identifier')
37
+ options.add_opt_simple(:client_secret, 'OAuth client secret')
38
+ options.add_opt_simple(:redirect_uri, 'OAuth redirect URI for web authentication')
39
+ options.add_opt_list(:auth, [:boot].concat(Oauth::STD_AUTH_TYPES), 'OAuth type of authentication')
40
+ options.add_opt_simple(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
41
+ options.add_opt_simple(:passphrase, 'RSA private key passphrase')
42
+ options.add_opt_simple(:shared_folder, 'Shared folder source for package files')
43
+ options.set_option(:auth, :jwt)
37
44
  options.parse_options!
38
45
  end
39
46
 
40
47
  def set_api
41
- @faxpex5_api_base_url = options.get_option(:url,is_type: :mandatory).gsub(%r{/+$},'')
42
- @faxpex5_api_auth_url = "#{@faxpex5_api_base_url}/auth"
43
- faxpex5_api_v5_url = "#{@faxpex5_api_base_url}/api/v5"
44
- case options.get_option(:auth,is_type: :mandatory)
48
+ @faspex5_api_base_url = options.get_option(:url, is_type: :mandatory).gsub(%r{/+$}, '')
49
+ @faspex5_api_auth_url = "#{@faspex5_api_base_url}/auth"
50
+ faspex5_api_v5_url = "#{@faspex5_api_base_url}/api/v5"
51
+ case options.get_option(:auth, is_type: :mandatory)
45
52
  when :boot
46
53
  # the password here is the token copied directly from browser in developer mode
47
54
  @api_v5 = Rest.new({
48
- base_url: faxpex5_api_v5_url,
49
- headers: {'Authorization' => options.get_option(:password,is_type: :mandatory)}
55
+ base_url: faspex5_api_v5_url,
56
+ headers: {'Authorization' => options.get_option(:password, is_type: :mandatory)}
50
57
  })
51
58
  when :web
52
59
  # opens a browser and ask user to auth using web
53
60
  @api_v5 = Rest.new({
54
- base_url: faxpex5_api_v5_url,
61
+ base_url: faspex5_api_v5_url,
55
62
  auth: {
56
- type: :oauth2,
57
- base_url: @faxpex5_api_auth_url,
58
- crtype: :web,
59
- client_id: options.get_option(:client_id,is_type: :mandatory),
60
- web: {redirect_uri: options.get_option(:redirect_uri,is_type: :mandatory)}
63
+ type: :oauth2,
64
+ base_url: @faspex5_api_auth_url,
65
+ grant_method: :web,
66
+ client_id: options.get_option(:client_id, is_type: :mandatory),
67
+ web: {redirect_uri: options.get_option(:redirect_uri, is_type: :mandatory)}
61
68
  }})
62
69
  when :jwt
63
- app_client_id = options.get_option(:client_id,is_type: :mandatory)
70
+ app_client_id = options.get_option(:client_id, is_type: :mandatory)
64
71
  @api_v5 = Rest.new({
65
- base_url: faxpex5_api_v5_url,
72
+ base_url: faspex5_api_v5_url,
66
73
  auth: {
67
- type: :oauth2,
68
- base_url: @faxpex5_api_auth_url,
69
- crtype: :jwt,
70
- client_id: app_client_id,
71
- jwt: {
74
+ type: :oauth2,
75
+ base_url: @faspex5_api_auth_url,
76
+ grant_method: :jwt,
77
+ client_id: app_client_id,
78
+ jwt: {
72
79
  payload: {
73
80
  iss: app_client_id, # issuer
74
81
  aud: app_client_id, # audience TODO: ???
75
- sub: "user:#{options.get_option(:username,is_type: :mandatory)}" # subject also "client:#{app_client_id}" + auth user/pass
82
+ sub: "user:#{options.get_option(:username, is_type: :mandatory)}" # subject also "client:#{app_client_id}" + auth user/pass
76
83
  },
77
- #auth: {type: :basic, options.get_option(:username,is_type: :mandatory), options.get_option(:password,is_type: :mandatory),
78
- private_key_obj: OpenSSL::PKey::RSA.new(options.get_option(:private_key,is_type: :mandatory),options.get_option(:passphrase)),
84
+ # auth: {type: :basic, options.get_option(:username,is_type: :mandatory), options.get_option(:password,is_type: :mandatory),
85
+ private_key_obj: OpenSSL::PKey::RSA.new(options.get_option(:private_key, is_type: :mandatory), options.get_option(:passphrase)),
79
86
  headers: {typ: 'JWT'}
80
87
  }
81
88
  }})
82
89
  end
83
90
  end
84
91
 
85
- ACTIONS = %i[health version user bearer_token package admin].freeze
92
+ def normalize_recipients(parameters)
93
+ return unless parameters.key?('recipients')
94
+ raise 'Field recipients must be an Array' unless parameters['recipients'].is_a?(Array)
95
+ parameters['recipients'] = parameters['recipients'].map do |recipient_data|
96
+ # if just a string, assume it is the name
97
+ if recipient_data.is_a?(String)
98
+ result = @api_v5.read('contacts', {q: recipient_data, context: 'packages', type: [Rest::ARRAY_PARAMS, *RECIPIENT_TYPES]})[:data]
99
+ raise "No matching contact for #{recipient_data}" if result.empty?
100
+ raise "Multiple matching contact for #{recipient_data} : #{result['contacts'].map{|i|i['name']}.join(', ')}" unless 1.eql?(result['total_count'])
101
+ matched = result['contacts'].first
102
+ recipient_data = {
103
+ name: matched['name'],
104
+ recipient_type: matched['type']
105
+ }
106
+ end
107
+ # result for mapping
108
+ recipient_data
109
+ end
110
+ end
111
+
112
+ def wait_for_complete_upload(id)
113
+ parameters = options.get_option(:value)
114
+ spinner = nil
115
+ progress = nil
116
+ while true
117
+ status = @api_v5.read("packages/#{id}/upload_details")[:data]
118
+ # user asked to not follow
119
+ break unless parameters
120
+ if status['upload_status'].eql?('submitted')
121
+ if spinner.nil?
122
+ spinner = TTY::Spinner.new('[:spinner] :title', format: :classic)
123
+ spinner.start
124
+ end
125
+ spinner.update(title: status['upload_status'])
126
+ spinner.spin
127
+ elsif progress.nil?
128
+ progress = ProgressBar.create(
129
+ format: '%a %B %p%% %r Mbps %e',
130
+ rate_scale: lambda{|rate|rate / Environment::BYTES_PER_MEBIBIT},
131
+ title: 'progress',
132
+ total: status['bytes_total'].to_i)
133
+ else
134
+ progress.progress = status['bytes_written'].to_i
135
+ end
136
+ break if PACKAGE_TERMINATED.include?(status['upload_status'])
137
+ sleep(0.5)
138
+ end
139
+ status['id'] = id
140
+ return status
141
+ end
142
+
143
+ def lookup_entity(entity_type, property, value)
144
+ # TODO: what if too many, use paging ?
145
+ all = @api_v5.read(entity_type)[:data][entity_type]
146
+ found = all.find{|i|i[property].eql?(value)}
147
+ raise "No #{entity_type} with #{property} = #{value}" if found.nil?
148
+ return found
149
+ end
150
+
151
+ ACTIONS = %i[health version user bearer_token package shared_folders admin gateway postprocessing].freeze
86
152
 
87
153
  def execute_action
88
- set_api
89
154
  command = options.get_next_command(ACTIONS)
155
+ set_api unless command.eql?(:postprocessing)
90
156
  case command
91
157
  when :version
92
158
  return { type: :single_object, data: @api_v5.read('version')[:data] }
93
159
  when :health
94
160
  nagios = Nagios.new
95
161
  begin
96
- result=Rest.new(base_url: @faxpex5_api_base_url).read('health')[:data]
97
- result.each do |k,v|
98
- nagios.add_ok(k,v.to_s)
162
+ result = Rest.new(base_url: @faspex5_api_base_url).read('health')[:data]
163
+ result.each do |k, v|
164
+ nagios.add_ok(k, v.to_s)
99
165
  end
100
166
  rescue StandardError => e
101
- nagios.add_critical('faspex api',e.to_s)
167
+ nagios.add_critical('faspex api', e.to_s)
102
168
  end
103
169
  return nagios.result
104
170
  when :user
@@ -108,88 +174,187 @@ module Aspera
108
174
  when :show
109
175
  return { type: :single_object, data: @api_v5.read('account/preferences')[:data] }
110
176
  when :modify
111
- @api_v5.update('account/preferences',options.get_next_argument('modified parameters (Hash)'))
177
+ @api_v5.update('account/preferences', options.get_next_argument('modified parameters', type: Hash))
112
178
  return Main.result_status('modified')
113
179
  end
114
180
  end
115
181
  when :bearer_token
116
- return {type: :text,data: @api_v5.oauth_token}
182
+ return {type: :text, data: @api_v5.oauth_token}
117
183
  when :package
118
- command = options.get_next_command(%i[list show send receive])
184
+ command = options.get_next_command(%i[list show send receive status])
119
185
  case command
120
186
  when :list
121
187
  parameters = options.get_option(:value)
122
188
  return {
123
189
  type: :object_list,
124
- data: @api_v5.read('packages',parameters)[:data]['packages'],
190
+ data: @api_v5.read('packages', parameters)[:data]['packages'],
125
191
  fields: %w[id title release_date total_bytes total_files created_time state]
126
192
  }
127
193
  when :show
128
194
  id = instance_identifier
129
195
  return {type: :single_object, data: @api_v5.read("packages/#{id}")[:data]}
196
+ when :status
197
+ status = wait_for_complete_upload(instance_identifier)
198
+ return {type: :single_object, data: status}
130
199
  when :send
131
- parameters = options.get_option(:value,is_type: :mandatory)
132
- raise CliBadArgument,'value must be hash, refer to API' unless parameters.is_a?(Hash)
133
- package = @api_v5.create('packages',parameters)[:data]
134
- # TODO: option to send from remote source
135
- transfer_spec = @api_v5.create("packages/#{package['id']}/transfer_spec/upload",{transfer_type: TRANSFER_CONNECT})[:data]
136
- transfer_spec.delete('authentication')
137
- return Main.result_transfer(transfer.start(transfer_spec,{src: :node_gen3}))
200
+ parameters = options.get_option(:value, is_type: :mandatory)
201
+ raise CliBadArgument, 'Value must be Hash, refer to API' unless parameters.is_a?(Hash)
202
+ normalize_recipients(parameters)
203
+ package = @api_v5.create('packages', parameters)[:data]
204
+ shared_folder = options.get_option(:shared_folder)
205
+ if shared_folder.nil?
206
+ # TODO: option to send from remote source or httpgw
207
+ transfer_spec = @api_v5.call(
208
+ operation: 'POST',
209
+ subpath: "packages/#{package['id']}/transfer_spec/upload",
210
+ headers: {'Accept' => 'application/json'},
211
+ url_params: {transfer_type: TRANSFER_CONNECT},
212
+ json_params: {paths: transfer.source_list}
213
+ )[:data]
214
+ transfer_spec.delete('authentication')
215
+ return Main.result_transfer(transfer.start(transfer_spec))
216
+ else
217
+ if !shared_folder.to_i.to_s.eql?(shared_folder)
218
+ shared_folder = lookup_entity('shared_folders', 'name', shared_folder)['id']
219
+ end
220
+ transfer_request = {shared_folder_id: shared_folder, paths: transfer.source_list}
221
+ # start remote transfer and get first status
222
+ result = @api_v5.create("packages/#{package['id']}/remote_transfer", transfer_request)[:data]
223
+ result['id'] = package['id']
224
+ unless result['status'].eql?('completed')
225
+ formatter.display_status("Package #{package['id']}")
226
+ result = wait_for_complete_upload(package['id'])
227
+ end
228
+ return {type: :single_object, data: result}
229
+ end
138
230
  when :receive
139
231
  pkg_type = 'received'
140
232
  pack_id = instance_identifier
141
233
  package_ids = [pack_id]
142
234
  skip_ids_data = []
143
235
  skip_ids_persistency = nil
144
- if options.get_option(:once_only,is_type: :mandatory)
236
+ if options.get_option(:once_only, is_type: :mandatory)
145
237
  # read ids from persistency
146
238
  skip_ids_persistency = PersistencyActionOnce.new(
147
239
  manager: @agents[:persistency],
148
240
  data: skip_ids_data,
149
- id: IdGenerator.from_list(['faspex_recv',options.get_option(:url,is_type: :mandatory),options.get_option(:username,is_type: :mandatory),pkg_type]))
241
+ id: IdGenerator.from_list([
242
+ 'faspex_recv',
243
+ options.get_option(:url, is_type: :mandatory),
244
+ options.get_option(:username, is_type: :mandatory),
245
+ pkg_type]))
150
246
  end
151
- if pack_id.eql?(VAL_ALL)
247
+ if VAL_ALL.eql?(pack_id)
152
248
  # TODO: if packages have same name, they will overwrite
153
249
  parameters = options.get_option(:value)
154
- parameters ||= {'type' => 'received','subtype' => 'mypackages','limit' => 1000}
155
- raise CliBadArgument,'value filter must be Hash (API GET)' unless parameters.is_a?(Hash)
156
- package_ids = @api_v5.read('packages',parameters)[:data]['packages'].map{|p|p['id']}
250
+ parameters ||= {'type' => 'received', 'subtype' => 'mypackages', 'limit' => 1000}
251
+ raise CliBadArgument, 'value filter must be Hash (API GET)' unless parameters.is_a?(Hash)
252
+ package_ids = @api_v5.read('packages', parameters)[:data]['packages'].map{|p|p['id']}
157
253
  package_ids.reject!{|i|skip_ids_data.include?(i)}
158
254
  end
159
255
  result_transfer = []
160
- package_ids.each do |pkgid|
256
+ package_ids.each do |pkg_id|
257
+ param_file_list = {}
258
+ begin
259
+ param_file_list['paths'] = transfer.source_list
260
+ rescue Aspera::Cli::CliBadArgument
261
+ # paths is optional
262
+ end
161
263
  # TODO: allow from sent as well ?
162
- transfer_spec = @api_v5.create("packages/#{pkgid}/transfer_spec/download",{transfer_type: TRANSFER_CONNECT, type: pkg_type})[:data]
264
+ transfer_spec = @api_v5.call(
265
+ operation: 'POST',
266
+ subpath: "packages/#{pkg_id}/transfer_spec/download",
267
+ headers: {'Accept' => 'application/json'},
268
+ url_params: {transfer_type: TRANSFER_CONNECT, type: pkg_type},
269
+ json_params: param_file_list
270
+ )[:data]
163
271
  transfer_spec.delete('authentication')
164
- statuses = transfer.start(transfer_spec,{src: :node_gen3})
165
- result_transfer.push({'package' => pkgid,Main::STATUS_FIELD => statuses})
272
+ statuses = transfer.start(transfer_spec)
273
+ result_transfer.push({'package' => pkg_id, Main::STATUS_FIELD => statuses})
166
274
  # skip only if all sessions completed
167
- skip_ids_data.push(pkgid) if TransferAgent.session_status(statuses).eql?(:success)
275
+ skip_ids_data.push(pkg_id) if TransferAgent.session_status(statuses).eql?(:success)
168
276
  end
169
277
  skip_ids_persistency&.save
170
278
  return Main.result_transfer_multiple(result_transfer)
171
279
  end # case package
280
+ when :shared_folders
281
+ all_shared_folders = @api_v5.read('shared_folders')[:data]['shared_folders']
282
+ case options.get_next_command(%i[list browse])
283
+ when :list
284
+ return {type: :object_list, data: all_shared_folders}
285
+ when :browse
286
+ shared_folder_id = instance_identifier
287
+ path = options.get_next_argument('folder path', mandatory: false) || '/'
288
+ node = all_shared_folders.find{|i|i['id'].eql?(shared_folder_id)}
289
+ raise "No such shared folder id #{shared_folder_id}" if node.nil?
290
+ result = @api_v5.call({
291
+ operation: 'POST',
292
+ subpath: "nodes/#{node['node_id']}/shared_folders/#{shared_folder_id}/browse",
293
+ headers: {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
294
+ json_params: {'path': path, 'filters': {'basenames': []}},
295
+ url_params: {offset: 0, limit: 100}
296
+ })[:data]
297
+ if result.key?('items')
298
+ return {type: :object_list, data: result['items']}
299
+ else
300
+ return {type: :single_object, data: result['self']}
301
+ end
302
+ end
172
303
  when :admin
173
- case options.get_next_command([:resource])
304
+ case options.get_next_command(%i[resource])
174
305
  when :resource
175
- res_type = options.get_next_command(%i[accounts contacts jobs workgroups shared_inboxes nodes oauth_clients registrations saml_configs metadata_profiles])
306
+ res_type = options.get_next_command(%i[accounts contacts jobs workgroups shared_inboxes nodes oauth_clients registrations saml_configs metadata_profiles
307
+ email_notifications])
176
308
  res_path = list_key = res_type.to_s
309
+ id_as_arg = false
177
310
  case res_type
178
311
  when :metadata_profiles
179
- res_path='configuration/metadata_profiles'
180
- list_key='profiles'
312
+ res_path = 'configuration/metadata_profiles'
313
+ list_key = 'profiles'
314
+ when :email_notifications
315
+ list_key = false
316
+ id_as_arg = 'type'
181
317
  end
182
318
  display_fields =
183
319
  case res_type
184
- when :accounts then [:all_but,'user_profile_data_attributes']
185
- when :oauth_clients then [:all_but,'public_key']
320
+ when :accounts then [:all_but, 'user_profile_data_attributes']
321
+ when :oauth_clients then [:all_but, 'public_key']
186
322
  end
187
323
  adm_api = @api_v5
188
324
  if res_type.eql?(:oauth_clients)
189
- adm_api = Rest.new(@api_v5.params.merge({base_url: @faxpex5_api_auth_url}))
325
+ adm_api = Rest.new(@api_v5.params.merge({base_url: @faspex5_api_auth_url}))
190
326
  end
191
- return entity_action(adm_api,res_path,item_list_key: list_key, display_fields: display_fields)
327
+ return entity_action(adm_api, res_path, item_list_key: list_key, display_fields: display_fields, id_as_arg: id_as_arg)
192
328
  end
329
+ when :gateway
330
+ require 'aspera/faspex_gw'
331
+ url = options.get_option(:value, is_type: :mandatory)
332
+ uri = URI.parse(url)
333
+ server = WebServerSimple.new(uri)
334
+ server.mount(uri.path, Faspex4GWServlet, @api_v5, nil)
335
+ trap('INT') { server.shutdown }
336
+ formatter.display_status("Faspex 4 gateway listening on #{url}")
337
+ Log.log.info("Listening on #{url}")
338
+ # this is blocking until server exits
339
+ server.start
340
+ return Main.result_status('Gateway terminated')
341
+ when :postprocessing
342
+ require 'aspera/faspex_postproc'
343
+ parameters = options.get_option(:value, is_type: :mandatory)
344
+ raise 'parameters must be Hash' unless parameters.is_a?(Hash)
345
+ parameters = parameters.symbolize_keys
346
+ raise 'Missing key: url' unless parameters.key?(:url)
347
+ uri = URI.parse(parameters[:url])
348
+ parameters[:processing] ||= {}
349
+ parameters[:processing][:root] = uri.path
350
+ server = WebServerSimple.new(uri, certificate: parameters[:certificate])
351
+ server.mount(uri.path, Faspex4PostProcServlet, parameters[:processing])
352
+ trap('INT') { server.shutdown }
353
+ formatter.display_status("Faspex 4 post processing listening on #{uri.port}")
354
+ Log.log.info("Listening on #{uri.port}")
355
+ # this is blocking until server exits
356
+ server.start
357
+ return Main.result_status('Gateway terminated')
193
358
  end # case command
194
359
  end # action
195
360
  end # Faspex5