aspera-cli 4.25.2 → 4.25.4

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.
@@ -102,7 +102,7 @@ module Aspera
102
102
  # @param destination_folder [String] Base folder
103
103
  # @param fld. [Array] List of fields of package
104
104
  def unique_folder(package_info, destination_folder, fld: nil, seq: false, opt: false)
105
- Aspera.assert_array_all(fld, String, type: Cli::BadArgument){'fld'}
105
+ Aspera.assert_array_all(fld, String, type: BadArgument){'fld'}
106
106
  Aspera.assert([1, 2].include?(fld.length)){'fld must have 1 or 2 elements'}
107
107
  folder = Environment.instance.sanitized_filename(package_info[fld[0]])
108
108
  if seq
@@ -181,7 +181,7 @@ module Aspera
181
181
  end
182
182
  myself = aoc_api.read('self')
183
183
  if auto_set_pub_key
184
- Aspera.assert(myself['public_key'].empty?, type: Cli::Error){'Public key is already set in profile (use --override=yes)'} unless option_override
184
+ Aspera.assert(myself['public_key'].empty?, type: Error){'Public key is already set in profile (use --override=yes)'} unless option_override
185
185
  formatter.display_status('Updating profile with the public key.')
186
186
  aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
187
187
  end
@@ -224,21 +224,17 @@ module Aspera
224
224
  @scope = new_scope
225
225
  end
226
226
 
227
- # create an API object with the same options, but with a different subpath
227
+ # Create an API object with the options from CLI, but with a different subpath
228
228
  # @param aoc_base_path [String] New subpath
229
229
  # @return [Api::AoC] API object for AoC (is Rest)
230
230
  def api_from_options(aoc_base_path)
231
- return new_with_options(
232
- Api::AoC,
233
- kwargs: {
234
- scope: @scope,
235
- subpath: aoc_base_path,
236
- secret_finder: config
237
- },
238
- option: {
239
- workspace: nil
240
- }
241
- )
231
+ return Api::AoC.new(**Oauth.args_from_options(
232
+ options,
233
+ defaults: {workspace: nil},
234
+ scope: @scope,
235
+ subpath: aoc_base_path,
236
+ secret_finder: config
237
+ ))
242
238
  end
243
239
 
244
240
  # AoC Rest object
@@ -256,11 +252,14 @@ module Aspera
256
252
  end
257
253
 
258
254
  # Generate or update Hash with workspace id and name (option), if not already set
259
- # @param hash [Hash,nil] Optional base hash (modified)
260
- # @param string [Boolean] true to set key as string, else as symbol
261
- # @param name [Boolean] include name
262
- # @return [Hash] with key `workspace_[id,name]` (symbol or string) only if defined
263
- def workspace_id_hash(hash: nil, string: false, name: false)
255
+ # @param hash [Hash,nil] Optional base `Hash` (modified)
256
+ # @param string [Boolean] `true` to set key as `String`, else as `Symbol`
257
+ # @param name [Boolean] Include name
258
+ # @return [Hash{Symbol, String => String}] the modified hash containing:
259
+ # * `workspace_id` [String] the unique identifier.
260
+ # * `workspace_name` [String] (optional) the name, included if +name+ is true.
261
+ # @note The key type (String or Symbol) depends on the +string+ parameter.
262
+ def workspace_id_hash(hash = nil, string: false, name: false)
264
263
  info = aoc_api.workspace
265
264
  hash = {} if hash.nil?
266
265
  fields = %i[id]
@@ -273,12 +272,12 @@ module Aspera
273
272
  return hash
274
273
  end
275
274
 
276
- # Get resource identifier from command line, either directly or from name.
275
+ # Get resource identifier from command line, either directly specifying the `id` or from `name` (percent selector).
277
276
  # @param resource_class_path url path for resource
278
277
  # @return identifier
279
278
  def get_resource_id_from_args(resource_class_path)
280
279
  return instance_identifier do |field, value|
281
- Aspera.assert(field.eql?('name'), type: Cli::BadArgument){'only selection by name is supported'}
280
+ Aspera.assert(field.eql?('name'), type: BadArgument){'only selection by name is supported'}
282
281
  aoc_api.lookup_by_name(resource_class_path, value)['id']
283
282
  end
284
283
  end
@@ -300,7 +299,7 @@ module Aspera
300
299
  query = query_read_delete(default: default_query)
301
300
  # caller may add specific modifications or checks to query
302
301
  yield(query) if block_given?
303
- result = aoc_api.read_with_paging(resource_class_path, base_query.merge(query).compact, formatter: formatter)
302
+ result = aoc_api.read_with_paging(resource_class_path, base_query.merge(query).compact)
304
303
  return Main.result_object_list(result[:items], fields: fields, total: result[:total])
305
304
  end
306
305
 
@@ -312,7 +311,7 @@ module Aspera
312
311
  # TODO : craft a query that looks for dropbox only in current workspace
313
312
  query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query.delete('dropbox_name'))['id']
314
313
  end
315
- workspace_id_hash(hash: query, string: true)
314
+ workspace_id_hash(query, string: true)
316
315
  # by default show dropbox packages only for dropboxes
317
316
  query['exclude_dropbox_packages'] = !query.key?('dropbox_id') unless query.key?('exclude_dropbox_packages')
318
317
  end
@@ -325,7 +324,7 @@ module Aspera
325
324
  Aspera.assert_type(query, Hash){'query'}
326
325
  PACKAGE_RECEIVED_BASE_QUERY.each{ |k, v| query[k] = v unless query.key?(k)}
327
326
  resolve_dropbox_name_default_ws_id(query)
328
- return aoc_api.read_with_paging('packages', query.compact, formatter: formatter)
327
+ return aoc_api.read_with_paging('packages', query.compact)
329
328
  end
330
329
 
331
330
  NODE4_EXT_COMMANDS = %i[transfer].concat(Node::COMMANDS_GEN4).freeze
@@ -741,111 +740,132 @@ module Aspera
741
740
  end
742
741
  end
743
742
 
744
- # Create a shared link for the given entity
745
- # @param purpose_public [String] send_package_to_dropbox or view_shared_file
746
- # @param shared_data [Hash] information for shared data
747
- # @param &block [Proc] Optional: called on creation
748
- def short_link_command(purpose_public:, **shared_data)
749
- link_type = options.get_next_argument('link type', accept_list: %i[public private])
750
- purpose_local = case link_type
751
- when :public
752
- case purpose_public
753
- when /package/ then 'send_package_to_dropbox'
754
- when /shared/ then 'token_auth_redirection'
755
- else Aspera.error_unexpected_value(purpose_public){'public link purpose'}
756
- end
757
- when :private then 'shared_folder_auth_link'
758
- else Aspera.error_unreachable_line
743
+ # Create a short link for the given entity: Shared folder or Shared Inbox
744
+ # Short link entity: `short_links` have:
745
+ # - a numerical id, e.g. `764412`
746
+ # - a resource type, e.g. `UrlToken`
747
+ # - a ressource id, e.g. `scQ7uXPbvQ`
748
+ # - a short URL path, e.g. `dxyRpT9`
749
+ # @param shared_data [Hash] Information for shared data: dropbox_id+name or file_id+node_id
750
+ # @param &perm_block [Proc] Optional: create/modify/delete permissions on node
751
+ def short_link_command(**shared_data, &perm_block)
752
+ link_type = options.get_next_argument('link access (public or private)', accept_list: %i[public private])
753
+ if shared_data.keys.sort == %i[dropbox_id name]
754
+ # Packages app, Shared inbox
755
+ token_purpose = 'send_package_to_dropbox'
756
+ short_link_purpose = link_type.eql?(:public) ? 'send_package_to_dropbox' : 'shared_folder_auth_link'
757
+ elsif shared_data.keys.sort == %i[file_id node_id]
758
+ # Files app, Shared folder
759
+ token_purpose = 'view_shared_file'
760
+ short_link_purpose = link_type.eql?(:public) ? 'token_auth_redirection' : 'shared_folder_auth_link'
761
+ else
762
+ Aspera.error_unexpected_value(shared_data.keys)
759
763
  end
760
- command = options.get_next_command(%i[create delete list show modify])
764
+ command = options.get_next_command(%i[create delete list show] + (link_type.eql?(:public) ? %i[modify] : []))
761
765
  case command
762
766
  when :create
763
- entity_data = {
764
- purpose: purpose_local,
767
+ # Add workspace id
768
+ workspace_id_hash(shared_data)
769
+ create_payload = {
770
+ purpose: short_link_purpose,
765
771
  user_selected_name: nil
766
772
  }
767
773
  case link_type
768
774
  when :private
769
- entity_data[:data] = shared_data
775
+ create_payload[:data] = shared_data
770
776
  when :public
771
- entity_data[:expires_at] = nil
772
- entity_data[:password_enabled] = false
777
+ create_payload[:expires_at] = nil
778
+ create_payload[:password_enabled] = false
773
779
  shared_data[:name] = ''
774
- entity_data[:data] = {
780
+ create_payload[:data] = {
775
781
  aoc: true,
776
782
  url_token_data: {
777
783
  data: shared_data,
778
- purpose: purpose_public
784
+ purpose: token_purpose
779
785
  }
780
786
  }
781
787
  end
782
788
  custom_data = value_create_modify(command: command, default: {})
783
789
  access_levels = custom_data.delete('access_levels')
784
790
  if (pass = custom_data.delete('password'))
785
- entity_data[:data][:url_token_data][:password] = pass
786
- entity_data[:password_enabled] = true
791
+ create_payload[:data][:url_token_data][:password] = pass
792
+ create_payload[:password_enabled] = true
787
793
  end
788
- entity_data.deep_merge!(custom_data)
789
- result_create_short_link = aoc_api.create('short_links', entity_data)
790
- # public: Creation: permission on node
791
- yield(result_create_short_link['resource_id'], access_levels) if block_given? && link_type.eql?(:public)
794
+ create_payload.deep_merge!(custom_data)
795
+ result_create_short_link = aoc_api.create('short_links', create_payload)
796
+ # Creation: perm_block: permission on node
797
+ yield(:create, result_create_short_link['resource_id'], access_levels) if block_given? && link_type.eql?(:public)
792
798
  return Main.result_single_object(result_create_short_link)
793
- when :list, :show
799
+ when :delete, :list, :show, :modify
800
+ workspace_id_hash(shared_data)
794
801
  query = if link_type.eql?(:private)
795
802
  shared_data
796
803
  else
797
804
  {
798
805
  url_token_data: {
799
806
  data: shared_data,
800
- purpose: purpose_public
807
+ purpose: token_purpose
801
808
  }
802
809
  }
803
810
  end
804
811
  list_params = {
805
812
  json_query: query.to_json,
806
- purpose: purpose_local,
813
+ purpose: short_link_purpose,
807
814
  edit_access: true,
808
815
  # embed: 'updated_by_user',
809
816
  sort: '-created_at'
810
817
  }
811
- return result_list('short_links', fields: Formatter.all_but('data'), base_query: list_params) if command.eql?(:list)
812
- one_id = instance_identifier
813
- found = aoc_api.read_with_paging('short_links', list_params, formatter: formatter)[:items].find{ |item| item['id'].eql?(one_id)}
814
- raise Cli::BadIdentifier.new('Short link', one_id) if found.nil?
815
- return Main.result_single_object(found, fields: Formatter.all_but('data'))
816
- when :modify
817
- raise Cli::BadArgument, 'Only public links can be modified' unless link_type.eql?(:public)
818
- node_file = shared_data.slice(:node_id, :file_id)
819
- entity_data = {
820
- data: {
821
- url_token_data: {
822
- data: node_file
818
+ short_list = aoc_api.read_with_paging('short_links', list_params.merge(query_read_delete(default: {})).compact)
819
+ case command
820
+ when :delete
821
+ one_id = instance_identifier(description: 'short link id')
822
+ if link_type.eql?(:public)
823
+ found = short_list[:items].find{ |item| item['id'].eql?(one_id)}
824
+ raise BadIdentifier.new('Short link', one_id) if found.nil?
825
+ yield(:delete, found['resource_id'], nil)
826
+ end
827
+ aoc_api.delete("short_links/#{one_id}", {
828
+ edit_access: true,
829
+ json_query: shared_data.to_json
830
+ })
831
+ return Main.result_status('deleted')
832
+ when :list
833
+ return Main.result_object_list(short_list[:items], fields: Formatter.all_but('data'), total: short_list[:total])
834
+ when :show
835
+ one_id = instance_identifier(description: 'short link id')
836
+ found = short_list[:items].find{ |item| item['id'].eql?(one_id)}
837
+ raise BadIdentifier.new('Short link', one_id) if found.nil?
838
+ return Main.result_single_object(found, fields: Formatter.all_but('data'))
839
+ when :modify
840
+ one_id = instance_identifier(description: 'short link id')
841
+ node_file = shared_data.slice(:node_id, :file_id)
842
+ modify_payload = {
843
+ edit_access: true,
844
+ json_query: node_file
845
+ }
846
+ custom_data = value_create_modify(command: command)
847
+ if (pass = custom_data.delete('password'))
848
+ modify_payload[:password_enabled] = true
849
+ modify_payload[:data] = {
850
+ url_token_data: {
851
+ password: pass,
852
+ data: node_file
853
+ }
823
854
  }
824
- },
825
- json_query: node_file
826
- }
827
- one_id = instance_identifier
828
- custom_data = value_create_modify(command: command, default: {})
829
- if (pass = custom_data.delete('password'))
830
- entity_data[:data][:url_token_data][:password] = pass
831
- entity_data[:password_enabled] = true
832
- end
833
- entity_data.deep_merge!(custom_data)
834
- aoc_api.update("short_links/#{one_id}", entity_data)
835
- return Main.result_status('modified')
836
- when :delete
837
- one_id = instance_identifier
838
- shared_data.delete(:workspace_id)
839
- delete_params = {
840
- edit_access: true,
841
- json_query: shared_data.to_json
842
- }
843
- aoc_api.delete("short_links/#{one_id}", delete_params)
844
- if link_type.eql?(:public)
845
- # TODO: get permission id..
846
- # shared_apfid[:api].delete('permissions', {ids: })
855
+ else
856
+ modify_payload[:password_enabled] = false
857
+ end
858
+ if custom_data.delete('access_levels')
859
+ # Modification: perm_block: permission on node
860
+ found = short_list[:items].find{ |item| item['id'].eql?(one_id)}
861
+ raise BadIdentifier.new('Short link', one_id) if found.nil?
862
+ yield(:update, found['resource_id'], access_levels)
863
+ end
864
+ modify_payload.deep_merge!(custom_data)
865
+ aoc_api.update("short_links/#{one_id}", modify_payload)
866
+ return Main.result_status('modified')
847
867
  end
848
- return Main.result_status('deleted')
868
+ else Aspera.error_unexpected_value(command)
849
869
  end
850
870
  end
851
871
 
@@ -936,24 +956,20 @@ module Aspera
936
956
  case options.get_next_command(%i[list show short_link])
937
957
  when :list
938
958
  default_query = {'embed[]' => 'dropbox', 'aggregate_permissions_by_dropbox' => true, 'sort' => 'dropbox_name'}
939
- workspace_id_hash(hash: default_query, string: true)
959
+ workspace_id_hash(default_query, string: true)
940
960
  return result_list('dropbox_memberships', fields: %w[dropbox_id dropbox.name], default_query: default_query)
941
961
  when :show
942
962
  return Main.result_single_object(aoc_api.read(get_resource_path_from_args('dropboxes')))
943
963
  when :short_link
944
- return short_link_command(
945
- purpose_public: 'send_package_to_dropbox',
946
- dropbox_id: get_resource_id_from_args('dropboxes'),
947
- name: '',
948
- **workspace_id_hash
949
- )
964
+ # TODO: check name
965
+ return short_link_command(dropbox_id: get_resource_id_from_args('dropboxes'), name: '')
950
966
  end
951
967
  when :send
952
968
  package_data = value_create_modify(command: package_command)
953
969
  new_user_option = options.get_option(:new_user_option)
954
970
  option_validate = options.get_option(:validate_metadata)
955
971
  # Works for both normal user auth and link auth.
956
- workspace_id_hash(hash: package_data, string: true) unless package_data.key?('workspace_id')
972
+ workspace_id_hash(package_data, string: true) unless package_data.key?('workspace_id')
957
973
  if !aoc_api.public_link.nil?
958
974
  aoc_api.assert_public_link_types(%w[send_package_to_user send_package_to_dropbox])
959
975
  box_type = aoc_api.public_link['purpose'].split('_').last
@@ -1042,7 +1058,7 @@ module Aspera
1042
1058
  return Main.result_object_list(result[:items], fields: display_fields, total: result[:total])
1043
1059
  when :delete
1044
1060
  return do_bulk_operation(command: package_command, values: instance_identifier) do |id|
1045
- Aspera.assert_values(id.class, [String, Integer]){'identifier'}
1061
+ Aspera.assert_type(id, String, Integer){'identifier'}
1046
1062
  aoc_api.delete("packages/#{id}")
1047
1063
  end
1048
1064
  when :modify
@@ -1068,29 +1084,42 @@ module Aspera
1068
1084
  )
1069
1085
  shared_apfid = home_node_api.resolve_api_fid(aoc_api.home[:file_id], folder_dest)
1070
1086
  return short_link_command(
1071
- purpose_public: 'view_shared_file',
1072
1087
  node_id: shared_apfid[:api].app_info[:node_info]['id'],
1073
- file_id: shared_apfid[:file_id],
1074
- **workspace_id_hash
1075
- ) do |resource_id, access_levels|
1076
- perm_data = {
1077
- 'file_id' => shared_apfid[:file_id],
1078
- 'access_id' => resource_id,
1079
- 'access_type' => 'user',
1080
- 'access_levels' => Api::AoC.expand_access_levels(access_levels),
1081
- 'tags' => {
1082
- 'url_token' => true,
1083
- 'folder_name' => File.basename(folder_dest),
1084
- 'created_by_name' => aoc_api.current_user_info['name'],
1085
- 'created_by_email' => aoc_api.current_user_info['email'],
1086
- 'access_key' => shared_apfid[:api].app_info[:node_info]['access_key'],
1087
- 'node' => shared_apfid[:api].app_info[:node_info]['host'],
1088
- **workspace_id_hash(string: true, name: true)
1089
- }
1090
- }
1091
- created_data = shared_apfid[:api].create('permissions', perm_data)
1092
- aoc_api.permissions_send_event(event_data: created_data, app_info: shared_apfid[:api].app_info)
1093
- end
1088
+ file_id: shared_apfid[:file_id]
1089
+ ) do |op, id, access_levels|
1090
+ case op
1091
+ when :create
1092
+ # `id` is the resource id
1093
+ perm_data = {
1094
+ 'file_id' => shared_apfid[:file_id],
1095
+ 'access_id' => id,
1096
+ 'access_type' => 'user',
1097
+ 'access_levels' => Api::AoC.expand_access_levels(access_levels),
1098
+ 'tags' => {
1099
+ 'url_token' => true,
1100
+ 'folder_name' => File.basename(folder_dest),
1101
+ 'created_by_name' => aoc_api.current_user_info['name'],
1102
+ 'created_by_email' => aoc_api.current_user_info['email'],
1103
+ 'access_key' => shared_apfid[:api].app_info[:node_info]['access_key'],
1104
+ 'node' => shared_apfid[:api].app_info[:node_info]['name'],
1105
+ **workspace_id_hash(string: true, name: true)
1106
+ }
1107
+ }
1108
+ created_data = shared_apfid[:api].create('permissions', perm_data)
1109
+ aoc_api.permissions_send_event(event_data: created_data, app_info: shared_apfid[:api].app_info)
1110
+ when :update
1111
+ # `id` is the permission_id
1112
+ found = shared_apfid[:api].read('permissions', {file_id: shared_apfid[:file_id], inherited: false, access_type: 'user', access_id: id}).find{ |i| i['access_id'].eql?(id)}
1113
+ raise Error, 'Short link not found: #{id}' if found.nil?
1114
+ shared_apfid[:api].update("permissions/#{found['id']}", {access_levels: Api::AoC.expand_access_levels(access_levels)})
1115
+ when :delete
1116
+ # `id` is the resource id, i.e. `access_id`
1117
+ found = shared_apfid[:api].read('permissions', {file_id: shared_apfid[:file_id], inherited: false, access_type: 'user', access_id: id}).first
1118
+ raise Error, 'Short link not found: #{id}' if found.nil?
1119
+ shared_apfid[:api].delete("permissions/#{found['id']}")
1120
+ else Aspera.error_unexpected_value(op)
1121
+ end
1122
+ end
1094
1123
  end
1095
1124
  when :automation
1096
1125
  change_api_scope(Api::AoC::Scope::ADMIN_USER)
@@ -22,7 +22,6 @@ module Aspera
22
22
  class << self
23
23
  def declare_options(options)
24
24
  options.declare(:query, 'Additional filter for for some commands (list/delete)', allowed: [Hash, Array, NilClass])
25
- options.declare(:property, 'Name of property to set (modify operation)')
26
25
  options.declare(:bulk, 'Bulk operation (only some)', allowed: Allowed::TYPES_BOOLEAN, default: false)
27
26
  options.declare(:bfail, 'Bulk operation error handling', allowed: Allowed::TYPES_BOOLEAN, default: true)
28
27
  end
@@ -70,25 +69,25 @@ module Aspera
70
69
  # Resource identifier as positional parameter
71
70
  #
72
71
  # @param description [String] description of the identifier
73
- # @param block [Proc] block to search for identifier based on attribute value
72
+ # @param &block [Proc] block to search for identifier based on attribute value
74
73
  # @return [String, Array] identifier or list of ids
75
- def instance_identifier(description: 'identifier', &block)
74
+ def instance_identifier(description: 'identifier')
76
75
  res_id = options.get_next_argument(description, multiple: options.get_option(:bulk)) if res_id.nil?
77
76
  # Can be an Array
78
77
  if res_id.is_a?(String) && (m = Base.percent_selector(res_id))
79
- Aspera.assert(block, type: Cli::BadArgument){"Percent syntax for #{description} not supported in this context"}
78
+ Aspera.assert(block_given?, type: Cli::BadArgument){"Percent syntax for #{description} not supported in this context"}
80
79
  res_id = yield(m[:field], m[:value])
81
80
  end
82
81
  return res_id
83
82
  end
84
83
 
85
84
  # For create and delete operations: execute one action or multiple if bulk is yes
86
- # @param command [Symbol] operation: :create, :delete, ...
87
- # @param descr [String] description of the value
88
- # @param values [Object] the value(s), or the type of value to get from user
89
- # @param id_result [String] key in result hash to use as identifier
90
- # @param fields [Array] fields to display
91
- # @param &block [Proc] block to execute for each value
85
+ # @param command [Symbol] Operation: :create, :delete, ...
86
+ # @param descr [String] Description of the value
87
+ # @param values [Object] Value(s), or type of value to get from user
88
+ # @param id_result [String] Key in result hash to use as identifier
89
+ # @param fields [Array] Fields to display
90
+ # @param &block [Proc] Block to execute for each value
92
91
  def do_bulk_operation(command:, descr: nil, values: Hash, id_result: 'id', fields: :default)
93
92
  Aspera.assert(block_given?){'missing block'}
94
93
  is_bulk = options.get_option(:bulk)
@@ -178,7 +177,7 @@ module Aspera
178
177
  api.delete(
179
178
  entity,
180
179
  nil,
181
- content_type: Rest::MIME_JSON,
180
+ content_type: Mime::JSON,
182
181
  body: {delete_style => one_res_id}
183
182
  )
184
183
  return Main.result_status('deleted')
@@ -209,20 +208,18 @@ module Aspera
209
208
  return Main.result_object_list(data, fields: display_fields) if data.empty? || data.first.is_a?(Hash)
210
209
  return Main.result_value_list(data)
211
210
  else
212
- raise "An error occurred: unexpected result type for list: #{data.class}"
211
+ Aspera.error_unexpected_value(data.class.name){'list type'}
213
212
  end
214
213
  when :modify
215
214
  parameters = value_create_modify(command: command)
216
- property = options.get_option(:property)
217
- parameters = {property => parameters} unless property.nil?
218
215
  api.update(one_res_path, parameters)
219
216
  return Main.result_status('modified')
220
217
  else
221
- raise "unknown action: #{command}"
218
+ Aspera.error_unexpected_value(command){'command'}
222
219
  end
223
220
  end
224
221
 
225
- # Query parameters in URL suitable for REST: list/GET and delete/DELETE
222
+ # Query parameters in URL suitable for REST: list/`GET` and delete/`DELETE`
226
223
  def query_read_delete(default: nil)
227
224
  # Dup default, as it could be frozen
228
225
  query = options.get_option(:query) || default.dup
@@ -267,7 +264,7 @@ module Aspera
267
264
  # @param entity [String,Symbol] API endpoint of entity to list
268
265
  # @param items_key [String] Key in the result to get the list of items (Default: same as `entity`)
269
266
  # @param query [Hash,nil] Additional query parameters
270
- # @return [Array] items, total_count
267
+ # @return [Array<(Array<Hash>, Integer)>] items, total_count
271
268
  def list_entities_limit_offset_total_count(
272
269
  api:,
273
270
  entity:,
@@ -303,9 +300,9 @@ module Aspera
303
300
  remain_pages -= 1 unless remain_pages.nil?
304
301
  break if remain_pages == 0
305
302
  offset += page_result[items_key].length
306
- formatter.long_operation_running
303
+ RestParameters.instance.spinner_cb.call("#{result.length} / #{total_count || '?'}")
307
304
  end
308
- formatter.long_operation_terminated
305
+ RestParameters.instance.spinner_cb.call(action: :success)
309
306
  return result, total_count
310
307
  end
311
308
 
@@ -191,7 +191,8 @@ module Aspera
191
191
  def setup_rest_and_transfer_runtime
192
192
  RestParameters.instance.user_agent = Info::CMD_NAME
193
193
  RestParameters.instance.progress_bar = @progress_bar
194
- RestParameters.instance.session_cb = lambda{ |http_session| update_http_session(http_session)}
194
+ RestParameters.instance.session_cb = ->(http_session){update_http_session(http_session)}
195
+ RestParameters.instance.spinner_cb = ->(title = nil, action: :spin){formatter.long_operation(title, action: action)}
195
196
  # Check http options that are global
196
197
  keys_to_delete = []
197
198
  @option_http_options.each do |k, v|
@@ -210,7 +211,7 @@ module Aspera
210
211
  keys_to_delete.each{ |k| @option_http_options.delete(k)}
211
212
  OAuth::Factory.instance.persist_mgr = persistency if @option_cache_tokens
212
213
  OAuth::Web.additional_info = "#{Info::CMD_NAME} v#{Cli::VERSION}"
213
- Transfer::Parameters.file_list_folder = File.join(@main_folder, FILELIST_FOLDERNAME)
214
+ Transfer::Parameters.file_list_folder = File.join(@main_folder, FILE_LIST_FOLDER_NAME)
214
215
  RestErrorAnalyzer.instance.log_file = File.join(@main_folder, REST_EXCEPTIONS_LOG_FILENAME)
215
216
  # Register aspera REST call error handlers
216
217
  RestErrorsAspera.register_handlers
@@ -565,43 +566,6 @@ module Aspera
565
566
  raise Cli::Error, e.to_s
566
567
  end
567
568
 
568
- def execute_connect_action
569
- command = options.get_next_command(%i[list info version])
570
- if %i[info version].include?(command)
571
- connect_id = options.get_next_argument('id or title')
572
- one_res = Products::Connect.instance.versions.find{ |i| i['id'].eql?(connect_id) || i['title'].eql?(connect_id)}
573
- raise Cli::BadIdentifier.new(:connect, connect_id) if one_res.nil?
574
- end
575
- case command
576
- when :list
577
- return Main.result_object_list(Products::Connect.instance.versions, fields: %w[id title version])
578
- when :info
579
- one_res.delete('links')
580
- return Main.result_single_object(one_res)
581
- when :version
582
- all_links = one_res['links']
583
- command = options.get_next_command(%i[list download open])
584
- if %i[download open].include?(command)
585
- link_title = options.get_next_argument('title or rel')
586
- one_link = all_links.find{ |i| i['title'].eql?(link_title) || i['rel'].eql?(link_title)}
587
- raise "no such value: #{link_title}" if one_link.nil?
588
- end
589
- case command
590
- when :list
591
- return Main.result_object_list(all_links)
592
- when :download
593
- archive_path = one_link['href']
594
- save_to_path = File.join(transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE), archive_path.gsub(%r{.*/}, ''))
595
- Products::Connect.instance.cdn_api.call(operation: 'GET', subpath: archive_path, save_to_file: save_to_path)
596
- return Main.result_status("Downloaded: #{save_to_path}")
597
- when :open
598
- Environment.instance.open_uri(one_link['href'])
599
- return Main.result_status("Opened: #{one_link['href']}")
600
- end
601
- end
602
- Aspera.error_unreachable_line
603
- end
604
-
605
569
  def install_transfer_sdk
606
570
  asked_version = options.get_next_argument('transferd version', mandatory: false)
607
571
  name, version, folder = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: asked_version)
@@ -609,10 +573,8 @@ module Aspera
609
573
  end
610
574
 
611
575
  def execute_action_ascp
612
- command = options.get_next_command(%i[connect show products info install spec schema errors])
576
+ command = options.get_next_command(%i[show products info install spec schema errors])
613
577
  case command
614
- when :connect
615
- return execute_connect_action
616
578
  when :show
617
579
  return Main.result_text(Ascp::Installation.instance.path(:ascp))
618
580
  when :info
@@ -1198,7 +1160,7 @@ module Aspera
1198
1160
  # Folder containing custom plugins in user's config folder
1199
1161
  ASPERA_PLUGINS_FOLDERNAME = 'plugins'
1200
1162
  PERSISTENCY_FOLDER = 'persist_store'
1201
- FILELIST_FOLDERNAME = 'filelists'
1163
+ FILE_LIST_FOLDER_NAME = 'filelists'
1202
1164
  REST_EXCEPTIONS_LOG_FILENAME = 'rest_exceptions.log'
1203
1165
  ASPERA = 'aspera'
1204
1166
  SERVER_COMMAND = 'server'
@@ -1232,7 +1194,7 @@ module Aspera
1232
1194
  :CONF_PRESET_DEFAULTS,
1233
1195
  :CONF_PRESET_GLOBAL,
1234
1196
  :ASPERA_PLUGINS_FOLDERNAME,
1235
- :FILELIST_FOLDERNAME,
1197
+ :FILE_LIST_FOLDER_NAME,
1236
1198
  :REST_EXCEPTIONS_LOG_FILENAME,
1237
1199
  :ASPERA,
1238
1200
  :DEMO_SERVER,
@@ -51,7 +51,7 @@ module Aspera
51
51
  http = api.call(
52
52
  operation: 'POST',
53
53
  headers: {
54
- 'Content-type' => Rest::MIME_TEXT,
54
+ 'Content-type' => Mime::TEXT,
55
55
  'Accept' => 'application/xrds+xml'
56
56
  },
57
57
  ret: :resp
@@ -254,7 +254,7 @@ module Aspera
254
254
  package_creation_data = api_public_link.call(
255
255
  operation: 'POST',
256
256
  subpath: create_path,
257
- content_type: Rest::MIME_JSON,
257
+ content_type: Mime::JSON,
258
258
  body: package_create_params,
259
259
  headers: {'Accept' => 'text/javascript'},
260
260
  ret: :resp
@@ -418,9 +418,9 @@ module Aspera
418
418
  operation: 'POST',
419
419
  subpath: 'issue-token',
420
420
  query: {'direction' => 'down'},
421
- content_type: Rest::MIME_TEXT,
421
+ content_type: Mime::TEXT,
422
422
  body: xml_payload,
423
- headers: {'Accept' => Rest::MIME_TEXT, 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
423
+ headers: {'Accept' => Mime::TEXT, 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
424
424
  ret: :resp
425
425
  ).body
426
426
  end