Class: Aspera::Cli::Plugins::Aoc

Inherits:
Oauth show all
Defined in:
lib/aspera/cli/plugins/aoc.rb

Constant Summary collapse

FILES_COMMANDS =
(Node::COMMANDS_GEN4 + %i[transfer]).freeze
APP_TYPES =

Known fixed set of AoC application types (verified against API: activity, automation, files, packages)

%i[activity automation files packages].freeze
ADMIN_ACTIONS =
(%i[bearer_token application ats usage_reports analytics subscription auth_providers] + ADMIN_OBJECTS).freeze

Constants inherited from Oauth

Oauth::AUTH_OPTIONS, Oauth::AUTH_TYPES

Constants inherited from Base

Base::FILTER_ARGS

Instance Attribute Summary

Attributes inherited from Base

#context, #help_path

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Oauth

kwargs_from_options

Methods inherited from BasicAuth

#basic_auth_api, #basic_auth_params

Methods inherited from Base

#action_for, #add_manual_header, application_name, #bulk_result, command, command_registry, commands_under, #config, crud_commands, declare_options, define_action_method, #dispatch_child, #dispatch_from_registry, #dispatch_leaf, #entity_create, #entity_delete, entity_display_name, #entity_list, #entity_modify, #entity_res_path, #entity_show, #execute_action, #execute_leaf, file_matcher, #formatter, #generate_help, #http_config, #invoke_action, option, #options, #persistency, #presets, #progress_bar, #query_read_delete, #resolve_argument, root_setup, #transfer, use_options, used_option_sources

Constructor Details

#initialize(**_) ⇒ Aoc

Returns a new instance of Aoc.



276
277
278
279
280
281
282
283
# File 'lib/aspera/cli/plugins/aoc.rb', line 276

def initialize(**_)
  super
  @cache_workspace_info = nil
  @cache_home_node_file = nil
  @cache_api_aoc = nil
  @scope = Api::AoC::Scope::USER
  options.parse_options!
end

Class Method Details

.aoc_res_cfg(res) ⇒ Hash

Returns ops:, id_result:, require_ws_id:, list_fields:, schema:, query_component:.

Returns:

  • (Hash)

    ops:, id_result:, require_ws_id:, list_fields:, schema:, query_component:



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/aspera/cli/plugins/aoc.rb', line 125

def aoc_res_cfg(res)
  cfg    = ADMIN_OBJECT_CONFIG.fetch(res, {})
  path   = aoc_res_path(res)
  ops    = cfg[:ops] || (Base::Operations::ALL + (cfg[:extra_ops] || []))
  schema = cfg[:create_schema] == false ? nil : Schema::Registry.req_body(Schema::Registry::AOC, "#{path}.post")
  {
    path:            path,
    ops:             ops,
    id_result:       cfg[:id_result] || 'id',
    require_ws_id:   cfg[:require_ws_id] || false,
    list_fields:     cfg.key?(:list_fields) ? cfg[:list_fields] : %w[id name],
    schema:          schema,
    query_component: Schema::Registry::AOC
  }
end

.aoc_res_path(res) ⇒ String

Returns AoC REST path for an admin resource type.

Returns:

  • (String)

    AoC REST path for an admin resource type



118
119
120
121
122
# File 'lib/aspera/cli/plugins/aoc.rb', line 118

def aoc_res_path(res)
  cfg = ADMIN_OBJECT_CONFIG.fetch(res, {})
  return cfg[:path] if cfg[:path]
  "#{res}s".gsub(/ys$/, 'ies')
end

.detect(base_url) ⇒ Hash, NilClass

Returns:



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/aspera/cli/plugins/aoc.rb', line 66

def detect(base_url)
  # no protocol ?
  base_url = "https://#{base_url}" unless base_url.match?(%r{^[a-z]{1,6}://})
  # only org provided ?
  base_url = "#{base_url}.#{Api::AoC::SAAS_DOMAIN_PROD}" unless base_url.include?('.')
  # AoC is only https
  return unless base_url.start_with?('https://')
  location = Rest.new(base_url: base_url, redirect_max: 0).call(operation: 'GET', subpath: 'auth/ping', exception: false, ret: :resp)['Location']
  return if location.nil?
  redirect_uri = URI.parse(location)
  od = Api::AoC.split_org_domain(URI.parse(base_url))
  return unless redirect_uri.path.end_with?("oauth2/#{od[:organization]}/login")
  # either in standard domain, or product name in page
  return {
    version: Api::AoC.saas_url?(base_url) ? 'SaaS' : 'Self-managed',
    url:     base_url
  }
end

.next_available_folder(base, always: false) ⇒ String

Get folder path that does not exist

Parameters:

  • base (String)

    Base folder path

  • always (Boolean) (defaults to: false)

    true always add number, false only if base folder already exists

Returns:

  • (String)

    Folder path that does not exist, with possible . extension



89
90
91
92
93
94
95
96
# File 'lib/aspera/cli/plugins/aoc.rb', line 89

def next_available_folder(base, always: false)
  counter = always ? 1 : 0
  loop do
    result = counter.zero? ? base : "#{base}.#{counter}"
    return result unless Dir.exist?(result)
    counter += 1
  end
end

DSL helper: register the 5 short_link leaf commands under the given parent path and define the corresponding action methods on base.

Parameters:

  • base (Class)

    the plugin class

  • parent_path (Array<Symbol>)

    full path ending with :short_link



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/aspera/cli/plugins/aoc.rb', line 145

def register_short_link_commands(base, parent_path)
  base.commands_under(parent_path) do
    base.command(
      :create, description: 'Create',
      arguments: [{name: :custom_data, type: Hash, mandatory: false, default: {}}]
    )
    base.command(
      :modify, description: 'Modify',
      arguments: [{name: :short_link_id, type: :identifier}, {name: :custom_data, type: Hash, mandatory: false, default: {}}]
    )
    base.command(:list, description: 'List short links')
    base.command(
      :show, description: 'Show a short link',
      arguments: [{name: :short_link_id, type: :identifier}]
    )
    base.command(
      :delete, description: 'Delete a short link',
      arguments: [{name: :short_link_id, type: :identifier}]
    )
  end
  base.define_action_method(parent_path + [:create]) do |custom_data: {}, **ctx|
    sl_exec_create(custom_data, **ctx)
  end
  base.define_action_method(parent_path + [:list]) do |**ctx|
    sl_exec_list(**sl_fetch_list(**ctx))
  end
  base.define_action_method(parent_path + [:show]) do |**ctx|
    sl_exec_show(**sl_fetch_list(**ctx))
  end
  base.define_action_method(parent_path + [:delete]) do |**ctx|
    sl_exec_delete(**sl_fetch_list(**ctx), **ctx)
  end
  base.define_action_method(parent_path + [:modify]) do |custom_data: {}, **ctx|
    sl_exec_modify(custom_data, **sl_fetch_list(**ctx), **ctx)
  end
end

.unique_folder(package_info, destination_folder, fld: nil, seq: false, opt: false) ⇒ Object

Get folder path that does not exist If it exists, an extension is added or a sequential number if extension == :seq

Parameters:

  • package_info (Hash)

    Package information

  • destination_folder (String)

    Base folder

  • fld (Array) (defaults to: nil)

    List of fields of package



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/aspera/cli/plugins/aoc.rb', line 104

def unique_folder(package_info, destination_folder, fld: nil, seq: false, opt: false)
  Aspera.assert_array_all(fld, String, type: BadArgument) { 'fld' }
  Aspera.assert_values(fld.length, [1, 2]) { 'fld length' }
  folder = Environment.instance.sanitized_filename(package_info[fld[0]])
  if seq
    folder = next_available_folder(folder, always: !opt)
  elsif fld[1] && (Dir.exist?(folder) || !opt)
    # NOTE: it might already exist
    folder = "#{folder}.#{Environment.instance.sanitized_filename(fld[1])}"
  end
  File.join(destination_folder, folder)
end

Instance Method Details

#action_admin_analytics_application_eventsObject

admin > analytics > application_events



1322
1323
1324
1325
# File 'lib/aspera/cli/plugins/aoc.rb', line 1322

def action_admin_analytics_application_events
  events = build_analytics_api.read("organizations/#{aoc_api.['organization_id']}/application_events")['application_events']
  Result::ObjectList.new(events)
end

#action_admin_analytics_files(event_resource_type:, event_resource_id:, event_uuid:) ⇒ Object

admin > analytics > files



1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
# File 'lib/aspera/cli/plugins/aoc.rb', line 1358

def action_admin_analytics_files(event_resource_type:, event_resource_id:, event_uuid:, **)
  event_resource_id =
    case event_resource_type
    when :organizations then aoc_api.['organization_id']
    when :users         then aoc_api.['id']
    when :nodes         then aoc_api.['read_only_home_node_id']
    else Aspera.error_unreachable_line
    end if event_resource_id.to_s.empty?
  filter = query_read_delete(default: {})
  filter['limit'] ||= 100
  events = build_analytics_api.read("#{event_resource_type}/#{event_resource_id}/transfers/#{event_uuid}/files", filter)['files']
  Result::ObjectList.new(events)
end

#action_admin_analytics_transfers(event_resource_type:, event_resource_id:) ⇒ Object

admin > analytics > transfers



1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
# File 'lib/aspera/cli/plugins/aoc.rb', line 1328

def action_admin_analytics_transfers(event_resource_type:, event_resource_id:, **)
  event_resource_id ||=
    case event_resource_type
    when :organizations then aoc_api.['organization_id']
    when :users         then aoc_api.['id']
    when :nodes         then aoc_api.['read_only_home_node_id']
    else Aspera.error_unreachable_line
    end
  filter = query_read_delete(default: {})
  filter['limit'] ||= 100
  if options.get_option(:once_only, mandatory: true)
    saved_date = []
    start_date_persistency = PersistencyActionOnce.new(
      manager: persistency,
      data:    saved_date,
      id:      IdGenerator.from_list('aoc_ana_date', options.get_option(:url, mandatory: true), aoc_api.workspace_info[:name], event_resource_type.to_s, event_resource_id)
    )
    start_date_time = saved_date.first
    stop_date_time  = Time.now.utc.strftime('%FT%T.%LZ')
    saved_date[0]   = stop_date_time
    filter['start_time'] = start_date_time unless start_date_time.nil?
    filter['stop_time']  = stop_date_time
  end
  events = build_analytics_api.read("#{event_resource_type}/#{event_resource_id}/transfers", filter)['transfers']
  start_date_persistency&.save
  events.each { |tr_event| context.mailer.send_email_template(values: {ev: tr_event}) } if !options.get_option(:notify_to).nil?
  Result::ObjectList.new(events)
end

#action_admin_application_membership_create(membership:) ⇒ Object



1276
1277
1278
1279
1280
1281
1282
# File 'lib/aspera/cli/plugins/aoc.rb', line 1276

def action_admin_application_membership_create(membership:, **)
  data = membership.dup
  app_type = data.delete('app_type')
  Aspera.assert_type(app_type, String) { 'app_type' }
  Aspera.assert_values(app_type.to_sym, APP_TYPES) { 'app_type' }
  Result::SingleObject.new(aoc_api.create("apps/#{app_type}/app_memberships", data))
end

#action_admin_application_membership_delete(membership_id:) ⇒ Object



1289
1290
1291
1292
# File 'lib/aspera/cli/plugins/aoc.rb', line 1289

def action_admin_application_membership_delete(membership_id:, **)
  aoc_api.delete("apps/app_memberships/#{membership_id}")
  Result::Status.new('deleted')
end

#action_admin_application_membership_show(membership_id:) ⇒ Object

admin > application > membership > show|delete



1285
1286
1287
# File 'lib/aspera/cli/plugins/aoc.rb', line 1285

def action_admin_application_membership_show(membership_id:, **)
  Result::SingleObject.new(aoc_api.read("apps/app_memberships/#{membership_id}", query_read_delete))
end

#action_admin_client_set_pub_key(private_key_pem:, client_id:) ⇒ Object

admin > client > set_pub_key



1452
1453
1454
1455
1456
1457
# File 'lib/aspera/cli/plugins/aoc.rb', line 1452

def action_admin_client_set_pub_key(private_key_pem:, client_id:, **)
  c = aoc_res_cfg(:client)
  the_public_key = OpenSSL::PKey::RSA.new(private_key_pem).public_key.to_s
  aoc_api.update("#{c[:path]}/#{client_id}", {jwt_grant_enabled: true, public_key: the_public_key})
  Result::Success.new
end

#action_admin_node_bearer_token(scope:, node_id:) ⇒ Object

admin > node > bearer_token



1481
1482
1483
1484
1485
# File 'lib/aspera/cli/plugins/aoc.rb', line 1481

def action_admin_node_bearer_token(scope:, node_id:, **)
  scope ||= Api::Node::Scope::ADMIN
  node_api = aoc_api.node_api_from(node_id: node_id, scope: scope)
  Result::Text.new(node_api.oauth.authorization)
end

#action_admin_node_update_status(node_id:) ⇒ Object

admin > node > update_status



1488
1489
1490
# File 'lib/aspera/cli/plugins/aoc.rb', line 1488

def action_admin_node_update_status(node_id:, **)
  Result::SingleObject.new(aoc_api.read("#{aoc_res_path(:node)}/#{node_id}/update_status"), fields: %w[status error_time error_message])
end

#action_admin_subscription_accountObject

admin > subscription > account



1301
1302
1303
1304
1305
# File 'lib/aspera/cli/plugins/aoc.rb', line 1301

def 
  org = aoc_api.read('organization')
  result = GraphQL.execute(api_from_options('bss/platform/graphql'), 'bss_subscription_account', {organization_id: org['id']})
  Result::SingleObject.new(result['aoc']['bssSubscription'])
end

#action_admin_subscription_usage(aggregate:, start_date:, end_date:) ⇒ Object

admin > subscription > usage



1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
# File 'lib/aspera/cli/plugins/aoc.rb', line 1308

def action_admin_subscription_usage(aggregate:, start_date:, end_date:, **)
  today      = Date.today
  aggregate  = :ALL if aggregate.nil?
  start_date = today.prev_year.strftime('%Y-%m-%d') if start_date.nil?
  end_date   = today.strftime('%Y-%m-%d') if end_date.nil?
  org    = aoc_api.read('organization')
  result = GraphQL.execute(
    api_from_options('bss/platform/graphql'), 'bss_subscription_usage',
    {organization_id: org['id'], aggregate: aggregate, startDate: start_date, endDate: end_date}
  )
  Result::SingleObject.new(result['aoc'])
end

#action_admin_workspace_dropbox_list(ws_res_id:) ⇒ Object

admin > workspace > dropbox > list



1498
1499
1500
1501
# File 'lib/aspera/cli/plugins/aoc.rb', line 1498

def action_admin_workspace_dropbox_list(ws_res_id:, **)
  query = options.get_option(:query) || {}
  Result::ObjectList.new(aoc_api.read('dropboxes', query.merge({'workspace_id' => ws_res_id})), fields: %w[id name description])
end

#action_admin_workspace_shared_folder_list(shared_folders:) ⇒ Object

admin > workspace > shared_folder > list



1512
1513
1514
# File 'lib/aspera/cli/plugins/aoc.rb', line 1512

def action_admin_workspace_shared_folder_list(shared_folders:, **)
  Result::ObjectList.new(shared_folders, fields: %w[id node_name node_id file_id file.path tags.aspera.files.workspace.share_as])
end

#action_admin_workspace_shared_folder_member_list(ws_res_id:, sf_item:) ⇒ Object

admin > workspace > shared_folder > member > list



1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
# File 'lib/aspera/cli/plugins/aoc.rb', line 1534

def action_admin_workspace_shared_folder_member_list(ws_res_id:, sf_item:, **)
  node_api = aoc_api.node_api_from(
    node_id:        sf_item['node_id'],
    workspace_id:   ws_res_id,
    workspace_name: nil,
    scope:          Api::Node::Scope::USER
  )
  result = node_api.read('permissions', {'file_id' => sf_item['file_id'], 'tag' => "aspera.files.workspace.id=#{ws_res_id}"})
  result.each do |item|
    item['member'] = begin
      if Api::AoC.workspace_access?(item)
        {'name' => '[Internal permission]'}
      else
        aoc_api.read("admin/#{item['access_type']}s/#{item['access_id']}") rescue {'name' => 'not found'}
      end
    rescue => e
      {'name' => e.to_s}
    end
  end
  # TODO : read users and group name and add, if query "include_members"
  Result::ObjectList.new(result, fields: %w[access_type access_id access_level last_updated_at member.name member.email member.system_group_type member.system_group])
end

#action_files_transfer(direction:, source_folder:) ⇒ Object

files > transfer



1245
1246
1247
1248
1249
1250
1251
1252
1253
# File 'lib/aspera/cli/plugins/aoc.rb', line 1245

def action_files_transfer(direction:, source_folder:, **)
  execute_nodegen4_command(
    :transfer, aoc_api.home[:node_id],
    file_id:            aoc_api.home[:file_id],
    scope:              Api::Node::Scope::USER,
    transfer_direction: direction,
    transfer_source:    source_folder
  )
end

#action_gateway(parameters: {}) ⇒ Object



1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
# File 'lib/aspera/cli/plugins/aoc.rb', line 1582

def action_gateway(parameters: {}, **)
  require 'aspera/faspex_gw'
  parameters = parameters.symbolize_keys
  uri = URI.parse(parameters.delete(:url) { WebServerSimple::DEFAULT_URL })
  server = WebServerSimple.new(uri, **parameters.slice(*WebServerSimple::PARAMS))
  Aspera.assert(parameters.except(*WebServerSimple::PARAMS).empty?) { "unexpected parameters: #{parameters.except(*WebServerSimple::PARAMS).keys}" }
  server.mount(uri.path, Faspex4GWServlet, aoc_api, aoc_api.workspace_info[:id])
  server.start
  return Result::Status.new('Gateway terminated')
end

#action_packages_delete(package_id:) ⇒ Object

packages > delete



1061
1062
1063
1064
1065
1066
# File 'lib/aspera/cli/plugins/aoc.rb', line 1061

def action_packages_delete(package_id:, **)
  bulk_result(package_id, command: :delete) do |one_id|
    Aspera.assert_type(one_id, String, Integer) { 'identifier' }
    aoc_api.delete("packages/#{one_id}")
  end
end

#action_packages_listObject

packages > list



1045
1046
1047
1048
1049
1050
1051
1052
1053
# File 'lib/aspera/cli/plugins/aoc.rb', line 1045

def action_packages_list
  result, max_items = list_all_packages_with_query
  skip_ids_persistency = package_persistency
  reject_packages_from_persistency(result[:items], skip_ids_persistency)
  result[:items] = result[:items][0, max_items] if max_items
  display_fields = PACKAGE_LIST_DEFAULT_FIELDS
  display_fields += ['workspace_id'] if aoc_api.workspace_info[:id].nil?
  Result::ObjectList.new(result[:items], fields: display_fields, total: result[:total])
end

#action_packages_modify(data:, package_id:) ⇒ Object

packages > modify



1069
1070
1071
1072
# File 'lib/aspera/cli/plugins/aoc.rb', line 1069

def action_packages_modify(data:, package_id:, **)
  aoc_api.update("packages/#{package_id}", data)
  Result::Status.new('modified')
end

#action_packages_receive(package_id:) ⇒ Object

packages > receive — package_id: from arguments:(:identifier) (or overridden by public_link)



989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
# File 'lib/aspera/cli/plugins/aoc.rb', line 989

def action_packages_receive(package_id:, **)
  ids_to_download = if aoc_api.public_link.nil?
    package_id
  else
    aoc_api.assert_public_link_types(['view_received_package'])
    aoc_api.public_link['data']['package_id']
  end
  skip_ids_persistency = package_persistency
  case ids_to_download
  when SpecialValues::INIT
    all_packages, = list_all_packages_with_query
    Aspera.assert(skip_ids_persistency, 'INIT requires option once_only')
    skip_ids_persistency.data.clear.concat(all_packages[:items].map { |e| e['id'] })
    skip_ids_persistency.save
    return Result::Status.new("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
  when SpecialValues::ALL
    all_packages, max_items = list_all_packages_with_query
    reject_packages_from_persistency(all_packages[:items], skip_ids_persistency)
    all_packages[:items] = all_packages[:items][0, max_items] if max_items
    ids_to_download = all_packages[:items].map { |e| e['id'] }
    formatter.display_status("Found #{ids_to_download.length} package(s).")
  else
    ids_to_download = [ids_to_download] unless ids_to_download.is_a?(Array)
  end
  ts_paths = transfer.ts_source_paths(default: ['.'])
  per_package_def = options.get_option(:package_folder).symbolize_keys
   = per_package_def.delete(:inf)
  destination_folder = transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE)
  result_transfer = []
  ids_to_download.each do |package_id|
    package_info = aoc_api.read("packages/#{package_id}")
    package_node_api = aoc_api.node_api_from(
      node_id: package_info['node_id'],
      package_info: package_info,
      **workspace_id_hash(name: true)
    )
    transfer_spec = package_node_api.transfer_spec_gen4(
      package_info['contents_file_id'],
      Transfer::Spec::DIRECTION_RECEIVE,
      {'paths'=> ts_paths}
    )
    transfer.user_transfer_spec['destination_root'] = self.class.unique_folder(package_info, destination_folder, **per_package_def) unless per_package_def.empty?
    dest_folder = transfer.user_transfer_spec['destination_root'] || destination_folder
    formatter.display_status(%Q{Downloading package: [#{package_info['id']}] "#{package_info['name']}" to [#{dest_folder}]})
    statuses = transfer.start(transfer_spec, rest_token: package_node_api)
    File.write(File.join(dest_folder, "#{package_id}.info.json"), package_info.to_json) if 
    result_transfer.push({'package' => package_id, Runner::STATUS_FIELD => statuses})
    if skip_ids_persistency && statuses.is_a?(Transfer::Result::Success)
      skip_ids_persistency.data.push(package_id)
      skip_ids_persistency.save
    end
  end
  return Runner.result_transfer_multiple(result_transfer)
end

#action_packages_send(data:) ⇒ Object

packages > send



971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
# File 'lib/aspera/cli/plugins/aoc.rb', line 971

def action_packages_send(data:, **)
  package_data = data
  new_user_option = options.get_option(:new_user_option)
  option_validate = options.get_option(:validate_metadata)
  workspace_id_hash(package_data, string: true) unless package_data.key?('workspace_id')
  if !aoc_api.public_link.nil?
    aoc_api.assert_public_link_types(%w[send_package_to_user send_package_to_dropbox])
    box_type = aoc_api.public_link['purpose'].split('_').last
    package_data['recipients'] = [{'id' => aoc_api.public_link['data']["#{box_type}_id"], 'type' => box_type}]
    package_data['workspace_id'] = aoc_api.public_link['data']['workspace_id']
  end
  package_data['encryption_at_rest'] = true if transfer.user_transfer_spec['content_protection'].eql?('encrypt')
  created_package = aoc_api.create_package_simple(package_data, option_validate, new_user_option)
  Runner.result_transfer(transfer.start(created_package[:spec], rest_token: created_package[:node]))
  return Result::SingleObject.new(created_package[:info])
end

#action_packages_show(package_id:) ⇒ Object

packages > show



1056
1057
1058
# File 'lib/aspera/cli/plugins/aoc.rb', line 1056

def action_packages_show(package_id:, **)
  Result::SingleObject.new(aoc_api.read("packages/#{package_id}"))
end

#action_reminderObject

--- handler methods ---



963
964
965
966
967
968
# File 'lib/aspera/cli/plugins/aoc.rb', line 963

def action_reminder
  user_email = options.get_option(:username, mandatory: true)
  no_auth_api = Api::AoC.new(url: options.get_option(:url), auth: :none)
  no_auth_api.create('organization_reminders', {email: user_email})
  return Result::Status.new("List of organizations user is member of, has been sent by e-mail to #{user_email}")
end

#aoc_apiApi::AoC

AoC Rest object

Returns:

  • (Api::AoC)

    API object for AoC (is Rest)



322
323
324
325
326
327
328
329
330
331
332
# File 'lib/aspera/cli/plugins/aoc.rb', line 322

def aoc_api
  if @cache_api_aoc.nil?
    @cache_api_aoc = api_from_options(Api::AoC::API_V1)
    transfer.httpgw_url_cb = lambda do
      organization = @cache_api_aoc.read('organization')
      # @cache_api_aoc.current_user_info['connect_disabled']
      organization['http_gateway_server_url'] if organization['http_gateway_enabled'] && organization['http_gateway_server_url']
    end
  end
  return @cache_api_aoc
end

#aoc_res_cfg(res) ⇒ Object



518
# File 'lib/aspera/cli/plugins/aoc.rb', line 518

def aoc_res_cfg(res)  = self.class.aoc_res_cfg(res)

#aoc_res_path(res) ⇒ Object

Instance delegators so instance methods can call aoc_res_path/aoc_res_cfg without self.class.



517
# File 'lib/aspera/cli/plugins/aoc.rb', line 517

def aoc_res_path(res) = self.class.aoc_res_path(res)

#api_from_options(base_path) ⇒ Api::AoC

Create an API object with the options from CLI, but with a different subpath

Parameters:

  • base_path (String)

    Base path for APIs.

Returns:

  • (Api::AoC)

    API object for AoC (is Rest)



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/aspera/cli/plugins/aoc.rb', line 297

def api_from_options(base_path)
  # Get all existing OAuth kwargs from `options`.
  api = Api::AoC.new(
    scope:         @scope,
    subpath:       base_path,
    secret_finder: context.secret_finder,
    **Oauth.kwargs_from_options(options)
  )
  # User set a workspace ?
  # @type [String, nil]
  workspace = options.get_option(:workspace)
  if !workspace.nil? && (m = Parser.percent_selector(workspace))
    case m[:field]
    when 'name' then api.ws_ids[:name] = m[:value]
    when 'id' then api.ws_ids[:id] = m[:value]
    else Aspera.error_unexpected_value(m[:field]) { 'workspace selector: only `name` or `id`' }
    end
  else
    api.ws_ids[:name] = workspace
  end
  api
end

#build_analytics_apiObject

Build analytics REST API (shared by action_admin_analytics_*)



526
527
528
529
530
531
# File 'lib/aspera/cli/plugins/aoc.rb', line 526

def build_analytics_api
  Rest.new(**aoc_api.params.deep_merge({
    base_url: "#{aoc_api.base_url.gsub('/api/v1', '')}/analytics/v2",
    auth:     {params: {scope: Api::AoC::Scope::ADMIN_USER}}
  }))
end

#build_ats_pluginAts

admin > ats — build and return an Ats plugin instance wired to the AoC ATS API. Used as delegate_instance: target so --help traverses the Ats registry.

Returns:

  • (Ats)

    configured Ats plugin instance



1462
1463
1464
1465
1466
1467
1468
# File 'lib/aspera/cli/plugins/aoc.rb', line 1462

def build_ats_plugin
  ats_api = Rest.new(**aoc_api.params.deep_merge({
    base_url: "#{aoc_api.base_url}/admin/ats/pub/v1",
    auth:     {params: {scope: Api::AoC::Scope::ADMIN_USER}}
  }))
  Ats.new(context: context, api: ats_api)
end

#change_api_scope(new_scope) ⇒ Object

Change API scope for subsequent calls, re-instantiate API object

Parameters:

  • new_scope (String)

    New scope



287
288
289
290
291
292
# File 'lib/aspera/cli/plugins/aoc.rb', line 287

def change_api_scope(new_scope)
  # Discard cache
  @cache_api_aoc = nil
  @scope = new_scope
  nil
end

#execute_nodegen4_command(command_repo, node_id, file_id: nil, scope: nil, transfer_direction: nil, transfer_source: nil, **resolved_args) ⇒ Object

Execute a node gen4 command starting at given node and file IDs. Arguments already resolved by the DSL (e.g. path:) are forwarded via resolved_args and injected into the dispatch context so node.rb does not re-consume them from the CLI.

Parameters:

  • command_repo (Symbol)

    Command to execute (from Node::COMMANDS_GEN4 or :transfer)

  • node_id (String)

    Node identifier

  • file_id (String, nil) (defaults to: nil)

    Root file id; if nil, the AK root file id is used

  • scope (String, nil) (defaults to: nil)

    node scope (Node::Scope::USER/ADMIN), or nil (requires secret)

  • transfer_direction (Symbol, nil) (defaults to: nil)

    :push or :pull (only for command_repo == :transfer)

  • transfer_source (String, nil) (defaults to: nil)

    source folder (only for command_repo == :transfer)

  • resolved_args (Hash)

    already-resolved CLI arguments (e.g. path:) forwarded to dispatch



428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/aspera/cli/plugins/aoc.rb', line 428

def execute_nodegen4_command(command_repo, node_id, file_id: nil, scope: nil, transfer_direction: nil, transfer_source: nil, **resolved_args)
  top_node_api = aoc_api.node_api_from(
    node_id:        node_id,
    scope:          scope,
    **workspace_id_hash(name: true)
  )
  file_id = top_node_api.read("access_keys/#{top_node_api.app_info.node_info['access_key']}")['root_file_id'] if file_id.nil?
  node_plugin = Node.new(context: context, api: top_node_api)
  case command_repo
  when *Node::COMMANDS_GEN4
    # For permission: the handler consumes the path first then re-dispatches to sub-commands.
    # Calling dispatch_from_registry with skip_setup would bypass path consumption and fail.
    return node_plugin.send(:"action_access_keys_do_#{command_repo}", do_root_file_id: file_id, **resolved_args) if command_repo.eql?(:permission)
    return node_plugin.dispatch_from_registry([:access_keys, :do, command_repo], {do_root_file_id: file_id, **resolved_args}, skip_setup: true)
  when :transfer
    # client side is agent
    # server side is transfer server
    # in same workspace
    push_pull = transfer_direction
    source_folder = transfer_source
    case push_pull
    when :push
      client_direction = Transfer::Spec::DIRECTION_SEND
      client_folder = source_folder
      server_folder = transfer.destination_folder(client_direction)
    when :pull
      client_direction = Transfer::Spec::DIRECTION_RECEIVE
      client_folder = transfer.destination_folder(client_direction)
      server_folder = source_folder
    else Aspera.error_unreachable_line
    end
    client_apifid = top_node_api.resolve_api_fid(file_id, client_folder)
    server_apifid = top_node_api.resolve_api_fid(file_id, server_folder)
    # force node as transfer agent
    transfer.agent_instance = Agent::Node.new(
      url:      client_apifid.node_api.base_url,
      username: client_apifid.node_api.app_info.node_info['access_key'],
      password: client_apifid.node_api.oauth.authorization,
      root_id:  client_apifid.file_id
    )
    # additional node to node TS info
    add_ts = {
      'remote_access_key'   => server_apifid.node_api.app_info.node_info['access_key'],
      'destination_root_id' => server_apifid.file_id,
      'source_root_id'      => client_apifid.file_id
    }
    return Runner.result_transfer(transfer.start(server_apifid.node_api.transfer_spec_gen4(
      server_apifid.file_id,
      client_direction,
      add_ts
    )))
  else Aspera.error_unexpected_value(command_repo) { 'command' }
  end
  Aspera.error_unreachable_line
end

#get_resource_id_from_args(resource_class_path) ⇒ String

Get resource identifier from command line, either directly specifying the id or from name (percent selector).

Parameters:

  • resource_class_path (String)

    url path for resource

Returns:



358
359
360
361
362
363
# File 'lib/aspera/cli/plugins/aoc.rb', line 358

def get_resource_id_from_args(resource_class_path)
  return options.instance_identifier do |field, value|
    Aspera.assert_values(field, ['name'], type: BadArgument) { 'selector field' }
    aoc_api.lookup_with_q(resource_class_path, value: value)['id']
  end
end

#get_resource_path_from_args(resource_class_path) ⇒ Object

Get resource path from command line



366
367
368
# File 'lib/aspera/cli/plugins/aoc.rb', line 366

def get_resource_path_from_args(resource_class_path)
  return "#{resource_class_path}/#{get_resource_id_from_args(resource_class_path)}"
end

#list_all_packages_with_queryArray(Hash, Integer, nil)

List all packages from the API using the current --query option. The special max key is extracted before the API call and returned separately, so callers that apply a post-API filter (e.g. once_only) can enforce the limit after filtering rather than before.

Returns:

  • (Array(Hash, Integer, nil))

    [items:,total: paging result, max (or nil)]



406
407
408
409
410
411
412
413
414
# File 'lib/aspera/cli/plugins/aoc.rb', line 406

def list_all_packages_with_query
  query = query_read_delete(default: {}, schema: Schema::Registry.query_params(Schema::Registry::AOC, 'packages'))
  Aspera.assert_type(query, Hash) { 'query' }
  PACKAGE_RECEIVED_BASE_QUERY.each { |k, v| query[k] = v unless query.key?(k) }
  resolve_dropbox_name_default_ws_id(query)
  # Extract `max` before paging so callers can apply it after post-API filtering
  max_items = query.delete(RestList::MAX_ITEMS)&.to_i
  return aoc_api.read_with_paging('packages', query.compact), max_items
end

#package_persistencyPersistencyActionOnce?

Returns persistency object if option once_only is used.

Returns:



567
568
569
570
571
572
573
574
575
576
577
578
579
580
# File 'lib/aspera/cli/plugins/aoc.rb', line 567

def package_persistency
  return unless options.get_option(:once_only, mandatory: true)
  # TODO: add query info to id
  PersistencyActionOnce.new(
    manager: persistency,
    data: [],
    id: IdGenerator.from_list(
      'aoc_recv',
      options.get_option(:url, mandatory: true),
      aoc_api.workspace_info[:id],
      aoc_api.additional_persistence_ids
    )
  )
end

#reject_packages_from_persistency(all_packages, skip_ids_persistency) ⇒ Object



582
583
584
585
586
# File 'lib/aspera/cli/plugins/aoc.rb', line 582

def reject_packages_from_persistency(all_packages, skip_ids_persistency)
  return if skip_ids_persistency.nil?
  skip_package = skip_ids_persistency.data.to_h { |i| [i, true] }
  all_packages.reject! { |pkg| skip_package[pkg['id']] }
end

#resolve_dropbox_name_default_ws_id(query) ⇒ Object

Translates dropbox_name to dropbox_id and fills current workspace_id



389
390
391
392
393
394
395
396
397
398
399
# File 'lib/aspera/cli/plugins/aoc.rb', line 389

def resolve_dropbox_name_default_ws_id(query)
  if query.key?('dropbox_name')
    # convenience: specify name instead of id
    Aspera.assert(!query.key?('dropbox_id'), type: BadArgument) { 'Use field dropbox_name or dropbox_id, not both' }
    # TODO : craft a query that looks for dropbox only in current workspace
    query['dropbox_id'] = aoc_api.lookup_with_q('dropboxes', value: query.delete('dropbox_name'))['id']
  end
  workspace_id_hash(query, string: true)
  # by default show dropbox packages only for dropboxes
  query['exclude_dropbox_packages'] = !query.key?('dropbox_id') unless query.key?('exclude_dropbox_packages')
end

#resolve_sf_item(shared_folders:, sf_id:) ⇒ Object Also known as: setup_admin_workspace_shared_folder_node, setup_admin_workspace_shared_folder_member

admin > workspace > shared_folder > node|member — sf_id: already in ctx via arguments:(:identifier)



1517
1518
1519
1520
1521
# File 'lib/aspera/cli/plugins/aoc.rb', line 1517

def resolve_sf_item(shared_folders:, sf_id:, **)
  sf_item = shared_folders.find { |i| i['id'].eql?(sf_id) }
  Aspera.assert(sf_item, 'shared folder not found')
  {sf_item: sf_item}
end

#result_list(resource_class_path, fields: nil, base_query: {}, default_query: {}, query_component: nil) {|query| ... } ⇒ Object

List all entities, given additional, default and user's queries

Parameters:

  • resource_class_path (String)

    path to query on API

  • fields (Array, nil) (defaults to: nil)

    fields to display

  • base_query (Hash) (defaults to: {})

    a query applied always

  • default_query (Hash) (defaults to: {})

    default query unless overridden by user

  • query_component (String, nil) (defaults to: nil)

    registry component key; when set, --query=help shows filter schema

Yield Parameters:

  • query (Hash)

    The user's or default query for modification



377
378
379
380
381
382
383
384
385
386
# File 'lib/aspera/cli/plugins/aoc.rb', line 377

def result_list(resource_class_path, fields: nil, base_query: {}, default_query: {}, query_component: nil)
  Aspera.assert_type(base_query, Hash)
  Aspera.assert_type(default_query, Hash)
  qs_path = query_component ? Schema::Registry.query_params(query_component, resource_class_path) : nil
  query = query_read_delete(default: default_query, schema: qs_path)
  # caller may add specific modifications or checks to query
  yield(query) if block_given?
  result = aoc_api.read_with_paging(resource_class_path, base_query.merge(query).compact)
  return Result::ObjectList.new(result[:items], fields: fields, total: result[:total])
end

#setup_admin_scopeObject

admin - setup: change API scope to admin once



1295
1296
1297
1298
# File 'lib/aspera/cli/plugins/aoc.rb', line 1295

def setup_admin_scope(**)
  change_api_scope(Api::AoC::Scope::ADMIN)
  {}
end

#setup_admin_workspace_dropbox(workspace_id:) ⇒ Object

admin > workspace > dropbox — res_id: already in ctx via arguments:(:identifier)



1493
1494
1495
# File 'lib/aspera/cli/plugins/aoc.rb', line 1493

def setup_admin_workspace_dropbox(workspace_id:, **)
  {ws_res_id: workspace_id}
end

#setup_admin_workspace_shared_folder(workspace_id:) ⇒ Object

admin > workspace > shared_folder — res_id: already in ctx via arguments:(:identifier)



1504
1505
1506
1507
1508
1509
# File 'lib/aspera/cli/plugins/aoc.rb', line 1504

def setup_admin_workspace_shared_folder(workspace_id:, **)
  resource_instance_path = "#{aoc_res_path(:workspace)}/#{workspace_id}"
  query = options.get_option(:query) || Api::AoC.workspace_access(workspace_id).merge({'admin' => true})
  shared_folders = aoc_api.read_with_paging("#{resource_instance_path}/permissions", query)[:items]
  {ws_res_id: workspace_id, shared_folders: shared_folders}
end

#setup_automation_apiObject

Build automation API and store in @automation_api ivar.



954
955
956
957
958
959
# File 'lib/aspera/cli/plugins/aoc.rb', line 954

def setup_automation_api(**)
  change_api_scope(Api::AoC::Scope::ADMIN_USER)
  Log.log.warn('BETA: work under progress')
  @automation_api = Rest.new(**aoc_api.params, base_url: aoc_api.base_url.gsub('/api/', '/automation/'))
  {}
end

setup: files > short_link Resolves the target folder, consumes link_type argument, computes purposes.

Returns:

  • (Hash)

    ctx keys: sl_shared_data, sl_link_type, sl_token_purpose, sl_short_link_purpose, sl_perm_block, sl_shared_apifid, sl_folder_dest



1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
# File 'lib/aspera/cli/plugins/aoc.rb', line 1086

def setup_files_short_link(folder_dest:, link_type:, **)
  home_node_api = aoc_api.node_api_from(
    node_id: aoc_api.home[:node_id],
    **workspace_id_hash(name: true)
  )
  shared_apifid = home_node_api.resolve_api_fid(aoc_api.home[:file_id], folder_dest)
  shared_data = {
    node_id: shared_apifid.node_api.app_info.node_info['id'],
    file_id: shared_apifid.file_id
  }
  token_purpose, short_link_purpose = short_link_purposes(shared_data, link_type)
  perm_block = lambda do |op, id, access_levels|
    case op
    when :create
      perm_data = {
        'file_id'       => shared_apifid.file_id,
        'access_id'     => id,
        'access_type'   => 'user',
        'access_levels' => Api::AoC.expand_access_levels(access_levels),
        'tags'          => {
          'url_token'        => true,
          'folder_name'      => File.basename(folder_dest),
          'created_by_name'  => aoc_api.['name'],
          'created_by_email' => aoc_api.['email'],
          'access_key'       => shared_apifid.node_api.app_info.node_info['access_key'],
          'node'             => shared_apifid.node_api.app_info.node_info['name'],
          **workspace_id_hash(string: true, name: true)
        }
      }
      created_data = shared_apifid.node_api.create('permissions', perm_data)
      aoc_api.permissions_send_event(event_data: created_data, app_info: shared_apifid.node_api.app_info)
    when :update
      found = shared_apifid.node_api.read('permissions', {file_id: shared_apifid.file_id, inherited: false, access_type: 'user', access_id: id}).find { |i| i['access_id'].eql?(id) }
      Aspera.assert(!found.nil?, type: Error) { "Short link not found: #{id}" }
      shared_apifid.node_api.update("permissions/#{found['id']}", {access_levels: Api::AoC.expand_access_levels(access_levels)})
    when :delete
      found = shared_apifid.node_api.read('permissions', {file_id: shared_apifid.file_id, inherited: false, access_type: 'user', access_id: id}).first
      Aspera.assert(!found.nil?, type: Error) { "Short link not found: #{id}" }
      shared_apifid.node_api.delete("permissions/#{found['id']}")
    else Aspera.error_unexpected_value(op)
    end
  end
  {
    sl_shared_data:        shared_data,
    sl_link_type:          link_type,
    sl_token_purpose:      token_purpose,
    sl_short_link_purpose: short_link_purpose,
    sl_perm_block:         perm_block
  }
end

setup: packages > shared_inboxes > short_link Reads dropbox_id, consumes link_type argument, computes purposes.

Returns:

  • (Hash)

    ctx keys: sl_shared_data, sl_link_type, sl_token_purpose, sl_short_link_purpose



1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
# File 'lib/aspera/cli/plugins/aoc.rb', line 1140

def setup_packages_short_link(link_type:, **)
  dropbox_id = get_resource_id_from_args('dropboxes')
  shared_data = {dropbox_id: dropbox_id, name: ''}
  token_purpose, short_link_purpose = short_link_purposes(shared_data, link_type)
  {
    sl_shared_data:        shared_data,
    sl_link_type:          link_type,
    sl_token_purpose:      token_purpose,
    sl_short_link_purpose: short_link_purpose,
    sl_perm_block:         nil
  }
end

#setup_workspace_displayObject

Display workspace info before dispatching files/packages sub-commands. Returns {} so it does not inject anything into ctx.



944
945
946
947
948
949
950
951
# File 'lib/aspera/cli/plugins/aoc.rb', line 944

def setup_workspace_display(**)
  formatter.display_status("Workspace: #{aoc_api.workspace_info[:name].to_s.red}#{' (default)' if aoc_api.default_workspace?}")
  if !aoc_api.private_link.nil?
    folder_name = aoc_api.node_api_from(node_id: aoc_api.home[:node_id]).read("files/#{aoc_api.home[:file_id]}")['name']
    formatter.display_status("Private Folder: #{folder_name}")
  end
  {}
end

Build the list_params hash used by delete/list/show/modify short link operations.

Returns:



552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/aspera/cli/plugins/aoc.rb', line 552

def short_link_list_params(shared_data:, link_type:, token_purpose:, short_link_purpose:, **)
  query = if link_type.eql?(:private)
    shared_data
  else
    {url_token_data: {data: shared_data, purpose: token_purpose}}
  end
  {
    json_query:  query.to_json,
    purpose:     short_link_purpose,
    edit_access: true,
    sort:        '-created_at'
  }
end

Compute short-link purposes from shared_data keys and link_type.

Parameters:

  • shared_data (Hash)

    :dropbox_id+:name or :file_id+:node_id

  • link_type (Symbol)

    :public or :private

Returns:

  • (Array(String,String))

    [token_purpose, short_link_purpose]



537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/aspera/cli/plugins/aoc.rb', line 537

def short_link_purposes(shared_data, link_type)
  if shared_data.keys.sort == %i[dropbox_id name]
    token_purpose = 'send_package_to_dropbox'
    short_link_purpose = link_type.eql?(:public) ? 'send_package_to_dropbox' : 'shared_folder_auth_link'
  elsif shared_data.keys.sort == %i[file_id node_id]
    token_purpose = 'view_shared_file'
    short_link_purpose = link_type.eql?(:public) ? 'token_auth_redirection' : 'shared_folder_auth_link'
  else
    Aspera.error_unexpected_value(shared_data.keys)
  end
  [token_purpose, short_link_purpose]
end

#sl_exec_create(custom_data = {}, sl_shared_data:, sl_link_type:, sl_token_purpose:, sl_short_link_purpose:, sl_perm_block:) ⇒ Object

Shared implementation for short_link > create



1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
# File 'lib/aspera/cli/plugins/aoc.rb', line 1154

def sl_exec_create(custom_data = {}, sl_shared_data:, sl_link_type:, sl_token_purpose:, sl_short_link_purpose:, sl_perm_block:, **)
  shared_data = sl_shared_data.dup
  workspace_id_hash(shared_data)
  create_payload = {purpose: sl_short_link_purpose, user_selected_name: nil}
  case sl_link_type
  when :private
    create_payload[:data] = shared_data
  when :public
    create_payload[:expires_at]       = nil
    create_payload[:password_enabled] = false
    shared_data[:name] = ''
    create_payload[:data] = {
      aoc:            true,
      url_token_data: {data: shared_data, purpose: sl_token_purpose}
    }
  end
  custom_data = {}
  access_levels = custom_data.delete('access_levels')
  if (pass = custom_data.delete('password'))
    create_payload[:data][:url_token_data][:password] = pass
    create_payload[:password_enabled] = true
  end
  create_payload.deep_merge!(custom_data)
  result_create_short_link = aoc_api.create('short_links', create_payload)
  sl_perm_block&.call(:create, result_create_short_link['resource_id'], access_levels) if sl_link_type.eql?(:public)
  Result::SingleObject.new(result_create_short_link)
end

#sl_exec_delete(sl_shared_data_ws:, sl_short_list:, sl_link_type:, sl_perm_block:, short_link_id: nil) ⇒ Object

Shared implementation for short_link > delete



1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
# File 'lib/aspera/cli/plugins/aoc.rb', line 1197

def sl_exec_delete(sl_shared_data_ws:, sl_short_list:, sl_link_type:, sl_perm_block:, short_link_id: nil, **)
  one_id = short_link_id
  if sl_link_type.eql?(:public)
    found = sl_short_list[:items].find { |item| item['id'].eql?(one_id) }
    raise BadIdentifier.new('Short link', one_id) if found.nil?
    sl_perm_block&.call(:delete, found['resource_id'], nil)
  end
  aoc_api.delete("short_links/#{one_id}", {edit_access: true, json_query: sl_shared_data_ws.to_json})
  Result::Status.new('deleted')
end

#sl_exec_list(sl_short_list:) ⇒ Object

Shared implementation for short_link > list



1209
1210
1211
# File 'lib/aspera/cli/plugins/aoc.rb', line 1209

def sl_exec_list(sl_short_list:, **)
  Result::ObjectList.new(sl_short_list[:items], fields: Formatter.all_but('data'), total: sl_short_list[:total])
end

#sl_exec_modify(custom_data = {}, sl_shared_data:, sl_short_list:, sl_link_type:, sl_perm_block:, short_link_id: nil) ⇒ Object

Shared implementation for short_link > modify



1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
# File 'lib/aspera/cli/plugins/aoc.rb', line 1222

def sl_exec_modify(custom_data = {}, sl_shared_data:, sl_short_list:, sl_link_type:, sl_perm_block:, short_link_id: nil, **)
  Aspera.assert_values(sl_link_type, [:public], type: Cli::BadArgument) { 'link_type' }
  one_id = short_link_id
  node_file = sl_shared_data.slice(:node_id, :file_id)
  modify_payload = {edit_access: true, json_query: node_file}
  custom_data = {}
  if (pass = custom_data.delete('password'))
    modify_payload[:password_enabled] = true
    modify_payload[:data] = {url_token_data: {password: pass, data: node_file}}
  else
    modify_payload[:password_enabled] = false
  end
  if custom_data.delete('access_levels')
    found = sl_short_list[:items].find { |item| item['id'].eql?(one_id) }
    raise BadIdentifier.new('Short link', one_id) if found.nil?
    sl_perm_block&.call(:update, found['resource_id'], nil)
  end
  modify_payload.deep_merge!(custom_data)
  aoc_api.update("short_links/#{one_id}", modify_payload)
  Result::Status.new('modified')
end

#sl_exec_show(sl_short_list:, short_link_id: nil) ⇒ Object

Shared implementation for short_link > show

Raises:



1214
1215
1216
1217
1218
1219
# File 'lib/aspera/cli/plugins/aoc.rb', line 1214

def sl_exec_show(sl_short_list:, short_link_id: nil, **)
  one_id = short_link_id
  found = sl_short_list[:items].find { |item| item['id'].eql?(one_id) }
  raise BadIdentifier.new('Short link', one_id) if found.nil?
  Result::SingleObject.new(found, fields: Formatter.all_but('data'))
end

#sl_fetch_list(sl_shared_data:, sl_link_type:, sl_token_purpose:, sl_short_link_purpose:) ⇒ Object

Shared implementation for short_link > delete|list|show|modify: fetch the short_list



1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
# File 'lib/aspera/cli/plugins/aoc.rb', line 1183

def sl_fetch_list(sl_shared_data:, sl_link_type:, sl_token_purpose:, sl_short_link_purpose:, **)
  shared_data = sl_shared_data.dup
  workspace_id_hash(shared_data)
  list_params = short_link_list_params(
    shared_data: shared_data, link_type: sl_link_type,
    token_purpose: sl_token_purpose, short_link_purpose: sl_short_link_purpose
  )
  {
    sl_short_list:     aoc_api.read_with_paging('short_links', list_params.merge(query_read_delete(default: {})).compact),
    sl_shared_data_ws: shared_data
  }
end

#wizard(wizard, app_url) ⇒ Hash

Returns :preset_value, :test_args.

Parameters:

  • wizard (Wizard)

    The wizard object

  • app_url (String)

    Tested URL

Returns:

  • (Hash)

    :preset_value, :test_args



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/aspera/cli/plugins/aoc.rb', line 186

def wizard(wizard, app_url)
  pub_link_info = Api::AoC.link_info(app_url)
  # public link case
  if pub_link_info.key?(:token)
    pub_api = Rest.new(base_url: "https://#{URI.parse(pub_link_info[:url]).host}/api/v1")
    pub_info = pub_api.read('env/url_token_check', {token: pub_link_info[:token]})
    preset_value = {
      link: app_url
    }
    preset_value[:password] = options.get_option(:password, mandatory: true) if pub_info['password_protected']
    return {
      preset_value: preset_value,
      test_args:    'organization'
    }
  end
  options.declare(:use_generic_client, description: 'Wizard: AoC: use global or org specific jwt client id', allowed: Type::BOOLEAN, default: Api::AoC.saas_url?(app_url))
  options.parse_options!
  # make username mandatory for jwt, this triggers interactive input
  wiz_username = options.get_option(:username, mandatory: true)
  wizard.check_email(wiz_username)
  # Set the pub key and jwt tag in the user's profile automatically
  auto_set_pub_key = false
  auto_set_jwt = false
  # use browser authentication to bootstrap
  use_browser_authentication = false
  private_key_path = wizard.ask_private_key(
    user: wiz_username,
    url: app_url,
    page: '👤 → Account Settings → Profile → Public Key'
  )
  client_id = options.get_option(:client_id)
  client_secret = options.get_option(:client_secret)
  if client_id.nil? || client_secret.nil?
    if options.get_option(:use_generic_client)
      client_id = client_secret = nil
      formatter.display_status('Using global client_id.')
    else
      formatter.display_status('Using organization specific client_id.')
      formatter.display_status('Please login to your Aspera on Cloud instance.'.red)
      formatter.display_status('Navigate to: 𓃑  → Admin → Integrations → API Clients')
      formatter.display_status('Check or create in integration:')
      formatter.display_status('- name: cli')
      formatter.display_status("- redirect uri: #{REDIRECT_LOCALHOST}")
      formatter.display_status('- origin: localhost')
      formatter.display_status('Use the generated client id and secret in the following prompts.'.red)
      Environment.instance.open_uri("#{app_url}/admin/integrations/api-clients")
      client_id = options.get_option(:client_id, mandatory: true)
      client_secret = options.get_option(:client_secret, mandatory: true)
      # use_browser_authentication = true
    end
  end
  if use_browser_authentication
    formatter.display_status('We will use web authentication to bootstrap.')
    auto_set_pub_key = true
    auto_set_jwt = true
    Aspera.error_not_implemented
    # aoc_api.oauth.grant_method = :web
    # aoc_api.oauth.scope = Api::AoC::Scope::ADMIN
    # aoc_api.oauth.specific_parameters[:redirect_uri] = REDIRECT_LOCALHOST
  end
  myself = aoc_api.read('self')
  if auto_set_pub_key
    Aspera.assert(myself['public_key'].empty?, 'Public key is already set in profile (use --override=yes)', type: Error) unless option_override
    formatter.display_status('Updating profile with the public key.')
    aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
  end
  if auto_set_jwt
    formatter.display_status('Enabling JWT for client')
    aoc_api.update("clients/#{options.get_option(:client_id)}", {'jwt_grant_enabled' => true, 'explicit_authorization_required' => false})
  end
  return {
    preset_value: {
      url:           app_url,
      username:      myself['email'],
      auth:          :jwt.to_s,
      private_key:   "@file:#{private_key_path}",
      client_id:     client_id,
      client_secret: client_secret
    }.compact,
    test_args:    'user profile show'
  }
end

#workspace_id_hash(hash = nil, string: false, name: false) ⇒ Hash{Symbol, String => String}

Note:

The key type (String or Symbol) depends on the string parameter.

Generate or update Hash with workspace id and name (option), if not already set

Parameters:

  • hash (Hash, nil) (defaults to: nil)

    Optional base Hash (modified)

  • string (Boolean) (defaults to: false)

    true to set key as String, else as Symbol

  • name (Boolean) (defaults to: false)

    Include name

Returns:

  • (Hash{Symbol, String => String})

    the modified hash containing:

    • workspace_id [String] the unique identifier.
    • workspace_name [String] (optional) the name, included if name is true.


342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/aspera/cli/plugins/aoc.rb', line 342

def workspace_id_hash(hash = nil, string: false, name: false)
  info = aoc_api.workspace_info
  hash = {} if hash.nil?
  fields = %i[id]
  fields.push(:name) if name
  fields.each do |i|
    k = "workspace_#{i}"
    k = k.to_sym unless string
    hash[k] = info[i] unless info[i].nil? || hash.key?(k)
  end
  return hash
end