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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +430 -406
- data/CONTRIBUTING.md +104 -93
- data/README.md +6 -3
- data/lib/aspera/api/aoc.rb +15 -11
- data/lib/aspera/api/cos_node.rb +4 -0
- data/lib/aspera/api/faspex.rb +35 -7
- data/lib/aspera/api/node.rb +81 -27
- data/lib/aspera/assert.rb +1 -1
- data/lib/aspera/cli/formatter.rb +27 -11
- data/lib/aspera/cli/hints.rb +7 -0
- data/lib/aspera/cli/manager.rb +51 -30
- data/lib/aspera/cli/plugins/aoc.rb +152 -123
- data/lib/aspera/cli/plugins/base.rb +16 -19
- data/lib/aspera/cli/plugins/config.rb +6 -44
- data/lib/aspera/cli/plugins/faspex.rb +4 -4
- data/lib/aspera/cli/plugins/faspex5.rb +92 -83
- data/lib/aspera/cli/plugins/node.rb +10 -15
- data/lib/aspera/cli/plugins/oauth.rb +26 -25
- data/lib/aspera/cli/plugins/preview.rb +3 -3
- data/lib/aspera/cli/plugins/shares.rb +15 -7
- data/lib/aspera/cli/special_values.rb +1 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +2 -1
- data/lib/aspera/colors.rb +7 -0
- data/lib/aspera/faspex_gw.rb +5 -5
- data/lib/aspera/faspex_postproc.rb +4 -4
- data/lib/aspera/log.rb +12 -11
- data/lib/aspera/markdown.rb +5 -0
- data/lib/aspera/node_simulator.rb +1 -1
- data/lib/aspera/oauth/base.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +2 -2
- data/lib/aspera/rest.rb +68 -48
- data/lib/aspera/rest_error_analyzer.rb +38 -36
- data/lib/aspera/rest_errors_aspera.rb +19 -18
- data/lib/aspera/transfer/spec.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
|
@@ -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:
|
|
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:
|
|
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
|
-
#
|
|
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
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
|
260
|
-
# @param string [Boolean] true to set key as
|
|
261
|
-
# @param name [Boolean]
|
|
262
|
-
# @return [Hash
|
|
263
|
-
|
|
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:
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
745
|
-
#
|
|
746
|
-
#
|
|
747
|
-
#
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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
|
-
|
|
764
|
-
|
|
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
|
-
|
|
775
|
+
create_payload[:data] = shared_data
|
|
770
776
|
when :public
|
|
771
|
-
|
|
772
|
-
|
|
777
|
+
create_payload[:expires_at] = nil
|
|
778
|
+
create_payload[:password_enabled] = false
|
|
773
779
|
shared_data[:name] = ''
|
|
774
|
-
|
|
780
|
+
create_payload[:data] = {
|
|
775
781
|
aoc: true,
|
|
776
782
|
url_token_data: {
|
|
777
783
|
data: shared_data,
|
|
778
|
-
purpose:
|
|
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
|
-
|
|
786
|
-
|
|
791
|
+
create_payload[:data][:url_token_data][:password] = pass
|
|
792
|
+
create_payload[:password_enabled] = true
|
|
787
793
|
end
|
|
788
|
-
|
|
789
|
-
result_create_short_link = aoc_api.create('short_links',
|
|
790
|
-
#
|
|
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:
|
|
807
|
+
purpose: token_purpose
|
|
801
808
|
}
|
|
802
809
|
}
|
|
803
810
|
end
|
|
804
811
|
list_params = {
|
|
805
812
|
json_query: query.to_json,
|
|
806
|
-
purpose:
|
|
813
|
+
purpose: short_link_purpose,
|
|
807
814
|
edit_access: true,
|
|
808
815
|
# embed: 'updated_by_user',
|
|
809
816
|
sort: '-created_at'
|
|
810
817
|
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
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
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
945
|
-
|
|
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(
|
|
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.
|
|
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
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
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
|
|
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'
|
|
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(
|
|
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]
|
|
87
|
-
# @param descr [String]
|
|
88
|
-
# @param values [Object]
|
|
89
|
-
# @param id_result [String]
|
|
90
|
-
# @param fields [Array]
|
|
91
|
-
# @param &block [Proc]
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
218
|
+
Aspera.error_unexpected_value(command){'command'}
|
|
222
219
|
end
|
|
223
220
|
end
|
|
224
221
|
|
|
225
|
-
# Query parameters in URL suitable for REST: list
|
|
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
|
-
|
|
303
|
+
RestParameters.instance.spinner_cb.call("#{result.length} / #{total_count || '?'}")
|
|
307
304
|
end
|
|
308
|
-
|
|
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 =
|
|
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,
|
|
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[
|
|
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
|
-
|
|
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
|
-
:
|
|
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' =>
|
|
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:
|
|
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:
|
|
421
|
+
content_type: Mime::TEXT,
|
|
422
422
|
body: xml_payload,
|
|
423
|
-
headers: {'Accept' =>
|
|
423
|
+
headers: {'Accept' => Mime::TEXT, 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
|
|
424
424
|
ret: :resp
|
|
425
425
|
).body
|
|
426
426
|
end
|