class Spaceship::PortalClient

rubocop:disable Metrics/ClassLength

Constants

PROTOCOL_VERSION

@!group Init and Login

Public Class Methods

hostname() click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 23
def self.hostname
  "https://developer.apple.com/services-account/#{PROTOCOL_VERSION}/"
end

Public Instance Methods

app_groups() click to toggle source

@!group App Groups

# File spaceship/lib/spaceship/portal/portal_client.rb, line 371
def app_groups
  paging do |page_number|
    r = request(:post, 'account/ios/identifiers/listApplicationGroups.action', {
      teamId: team_id,
      pageNumber: page_number,
      pageSize: page_size,
      sort: 'name=asc'
    })
    parse_response(r, 'applicationGroupList')
  end
end
apps(mac: false) click to toggle source

@!group Apps

# File spaceship/lib/spaceship/portal/portal_client.rb, line 120
def apps(mac: false)
  paging do |page_number|
    r = request(:post, "account/#{platform_slug(mac)}/identifiers/listAppIds.action", {
      teamId: team_id,
      pageNumber: page_number,
      pageSize: page_size,
      sort: 'name=asc'
    })
    parse_response(r, 'appIds')
  end
end
associate_cloud_containers_with_app(app, containers) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 166
def associate_cloud_containers_with_app(app, containers)
  ensure_csrf(Spaceship::Portal::CloudContainer)

  request(:post, 'account/ios/identifiers/assignCloudContainerToAppId.action', {
      teamId: team_id,
      appIdId: app.app_id,
      cloudContainers: containers.map(&:cloud_container)
  })

  details_for_app(app)
end
associate_groups_with_app(app, groups) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 153
def associate_groups_with_app(app, groups)
  ensure_csrf(Spaceship::Portal::AppGroup)

  request(:post, 'account/ios/identifiers/assignApplicationGroupToAppId.action', {
    teamId: team_id,
    appIdId: app.app_id,
    displayId: app.app_id,
    applicationGroups: groups.map(&:app_group_id)
  })

  details_for_app(app)
end
associate_merchants_with_app(app, merchants, mac) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 178
def associate_merchants_with_app(app, merchants, mac)
  ensure_csrf(Spaceship::Portal::Merchant)

  request(:post, "account/#{platform_slug(mac)}/identifiers/assignOMCToAppId.action", {
    teamId: team_id,
    appIdId: app.app_id,
    omcIds: merchants.map(&:merchant_id)
  })

  details_for_app(app)
end
certificates(types, mac: false) click to toggle source

@!group Certificates

# File spaceship/lib/spaceship/portal/portal_client.rb, line 577
def certificates(types, mac: false)
  paging do |page_number|
    r = request(:post, "account/#{platform_slug(mac)}/certificate/listCertRequests.action", {
      teamId: team_id,
      types: types.join(','),
      pageNumber: page_number,
      pageSize: page_size,
      sort: 'certRequestStatusCode=asc'
    })
    parse_response(r, 'certRequests')
  end
end
cloud_containers() click to toggle source

@!group Cloud Containers

# File spaceship/lib/spaceship/portal/portal_client.rb, line 408
def cloud_containers
  paging do |page_number|
    r = request(:post, 'account/cloudContainer/listCloudContainers.action', {
        teamId: team_id,
        pageNumber: page_number,
        pageSize: page_size,
        sort: 'name=asc'
    })
    result = parse_response(r, 'cloudContainerList')

    csrf_cache[Spaceship::Portal::CloudContainer] = self.csrf_tokens

    result
  end
end
create_app!(type, name, bundle_id, mac: false, enable_services: {}) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 202
def create_app!(type, name, bundle_id, mac: false, enable_services: {})
  # We moved the ensure_csrf to the top of this method
  # as we got some users with issues around creating new apps
  # https://github.com/fastlane/fastlane/issues/5813
  ensure_csrf(Spaceship::Portal::App)

  ident_params = case type.to_sym
                 when :explicit
                   {
                     type: 'explicit',
                     identifier: bundle_id,
                     inAppPurchase: 'on',
                     gameCenter: 'on'
                   }
                 when :wildcard
                   {
                     type: 'wildcard',
                     identifier: bundle_id
                   }
                 end

  params = {
    name: valid_name_for(name),
    teamId: team_id
  }
  params.merge!(ident_params)
  enable_services.each do |k, v|
    params[v.service_id.to_sym] = v.value
  end
  r = request(:post, "account/#{platform_slug(mac)}/identifiers/addAppId.action", params)
  parse_response(r, 'appId')
end
create_app_group!(name, group_id) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 383
def create_app_group!(name, group_id)
  ensure_csrf(Spaceship::Portal::AppGroup)

  r = request(:post, 'account/ios/identifiers/addApplicationGroup.action', {
    name: valid_name_for(name),
    identifier: group_id,
    teamId: team_id
  })
  parse_response(r, 'applicationGroup')
end
create_certificate!(type, csr, app_id = nil, mac = false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 590
def create_certificate!(type, csr, app_id = nil, mac = false)
  ensure_csrf(Spaceship::Portal::Certificate)

  r = request(:post, "account/#{platform_slug(mac)}/certificate/submitCertificateRequest.action", {
    teamId: team_id,
    type: type,
    csrContent: csr,
    appIdId: app_id, # optional
    specialIdentifierDisplayId: app_id, # For requesting Web Push certificates
  })
  parse_response(r, 'certRequest')
end
create_cloud_container!(name, identifier) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 424
def create_cloud_container!(name, identifier)
  ensure_csrf(Spaceship::Portal::CloudContainer)

  r = request(:post, 'account/cloudContainer/addCloudContainer.action', {
      name: valid_name_for(name),
      identifier: identifier,
      teamId: team_id
  })
  parse_response(r, 'cloudContainer')
end
create_device!(device_name, device_id, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 537
def create_device!(device_name, device_id, mac: false)
  ensure_csrf(Spaceship::Portal::Device)

  req = request(:post, "account/#{platform_slug(mac)}/device/addDevices.action", {
    teamId: team_id,
    deviceClasses: mac ? 'mac' : 'iphone',
    deviceNumbers: device_id,
    deviceNames: device_name,
    register: 'single'
  })

  devices = parse_response(req, 'devices')
  return devices.first unless devices.empty?

  validation_messages = parse_response(req, 'validationMessages').map { |message| message["validationUserMessage"] }.compact.uniq

  raise UnexpectedResponse.new, validation_messages.join('\n') unless validation_messages.empty?
  raise UnexpectedResponse.new, "Couldn't register new device, got this: #{parse_response(req)}"
end
create_key!(name: nil, service_configs: nil) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 780
def create_key!(name: nil, service_configs: nil)
  fetch_csrf_token_for_keys

  params = {
    name: name,
    serviceConfigurations: service_configs,
    teamId: team_id
  }

  response = request(:post, 'account/auth/key/create') do |req|
    req.headers['Content-Type'] = 'application/json'
    req.body = params.to_json
  end

  # response contains a list of keys with 1 item
  parse_response(response, 'keys').first
end
create_merchant!(name, bundle_id, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 346
def create_merchant!(name, bundle_id, mac: false)
  ensure_csrf(Spaceship::Portal::Merchant)

  r = request(:post, "account/#{platform_slug(mac)}/identifiers/addOMC.action", {
      name: name,
      identifier: bundle_id,
      teamId: team_id
  })
  parse_response(r, 'omcId')
end
create_passbook!(name, bundle_id) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 272
def create_passbook!(name, bundle_id)
  ensure_csrf(Spaceship::Portal::Passbook)

  r = request(:post, "account/ios/identifiers/addPassTypeId.action", {
      name: name,
      identifier: bundle_id,
      teamId: team_id
  })
  parse_response(r, 'passTypeId')
end
create_provisioning_profile!(name, distribution_method, app_id, certificate_ids, device_ids, mac: false, sub_platform: nil, template_name: nil) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 684
def create_provisioning_profile!(name, distribution_method, app_id, certificate_ids, device_ids, mac: false, sub_platform: nil, template_name: nil)
  ensure_csrf(Spaceship::Portal::ProvisioningProfile) do
    fetch_csrf_token_for_provisioning
  end

  params = {
    teamId: team_id,
    provisioningProfileName: name,
    appIdId: app_id,
    distributionType: distribution_method,
    certificateIds: certificate_ids,
    deviceIds: device_ids
  }
  params[:subPlatform] = sub_platform if sub_platform

  # if `template_name` is nil, Default entitlements will be used
  params[:template] = template_name if template_name

  r = request(:post, "account/#{platform_slug(mac)}/profile/createProvisioningProfile.action", params)
  parse_response(r, 'provisioningProfile')
end
create_website_push!(name, bundle_id, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 309
def create_website_push!(name, bundle_id, mac: false)
  ensure_csrf(Spaceship::Portal::WebsitePush)

  r = request(:post, "account/#{platform_slug(mac)}/identifiers/addWebsitePushId.action", {
      name: name,
      identifier: bundle_id,
      teamId: team_id
  })
  parse_response(r, 'websitePushId')
end
delete_app!(app_id, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 235
def delete_app!(app_id, mac: false)
  ensure_csrf(Spaceship::Portal::App)

  r = request(:post, "account/#{platform_slug(mac)}/identifiers/deleteAppId.action", {
    teamId: team_id,
    appIdId: app_id
  })
  parse_response(r)
end
delete_app_group!(app_group_id) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 394
def delete_app_group!(app_group_id)
  ensure_csrf(Spaceship::Portal::AppGroup)

  r = request(:post, 'account/ios/identifiers/deleteApplicationGroup.action', {
    teamId: team_id,
    applicationGroup: app_group_id
  })
  parse_response(r)
end
delete_merchant!(merchant_id, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 357
def delete_merchant!(merchant_id, mac: false)
  ensure_csrf(Spaceship::Portal::Merchant)

  r = request(:post, "account/#{platform_slug(mac)}/identifiers/deleteOMC.action", {
      teamId: team_id,
      omcId: merchant_id
  })
  parse_response(r)
end
delete_passbook!(passbook_id) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 283
def delete_passbook!(passbook_id)
  ensure_csrf(Spaceship::Portal::Passbook)

  r = request(:post, "account/ios/identifiers/deletePassTypeId.action", {
      teamId: team_id,
      passTypeId: passbook_id
  })
  parse_response(r)
end
delete_provisioning_profile!(profile_id, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 723
def delete_provisioning_profile!(profile_id, mac: false)
  fetch_csrf_token_for_provisioning
  r = request(:post, "account/#{platform_slug(mac)}/profile/deleteProvisioningProfile.action", {
    teamId: team_id,
    provisioningProfileId: profile_id
  })
  parse_response(r)
end
delete_website_push!(website_id, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 320
def delete_website_push!(website_id, mac: false)
  ensure_csrf(Spaceship::Portal::WebsitePush)

  r = request(:post, "account/#{platform_slug(mac)}/identifiers/deleteWebsitePushId.action", {
      teamId: team_id,
      websitePushId: website_id
  })
  parse_response(r)
end
details_for_app(app) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 132
def details_for_app(app)
  r = request(:post, "account/#{platform_slug(app.mac?)}/identifiers/getAppIdDetail.action", {
    teamId: team_id,
    appIdId: app.app_id
  })
  parse_response(r, 'appId')
end
devices(mac: false, include_disabled: false) click to toggle source

@!group Devices

# File spaceship/lib/spaceship/portal/portal_client.rb, line 506
def devices(mac: false, include_disabled: false)
  paging do |page_number|
    r = request(:post, "account/#{platform_slug(mac)}/device/listDevices.action", {
      teamId: team_id,
      pageNumber: page_number,
      pageSize: page_size,
      sort: 'name=asc',
      includeRemovedDevices: include_disabled
    })
    result = parse_response(r, 'devices')

    csrf_cache[Spaceship::Portal::Device] = self.csrf_tokens

    result
  end
end
devices_by_class(device_class, include_disabled: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 523
def devices_by_class(device_class, include_disabled: false)
  paging do |page_number|
    r = request(:post, 'account/ios/device/listDevices.action', {
      teamId: team_id,
      pageNumber: page_number,
      pageSize: page_size,
      sort: 'name=asc',
      deviceClasses: device_class,
      includeRemovedDevices: include_disabled
    })
    parse_response(r, 'devices')
  end
end
disable_device!(device_id, device_udid, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 557
def disable_device!(device_id, device_udid, mac: false)
  request(:post, "https://developer.apple.com/services-account/#{PROTOCOL_VERSION}/account/#{platform_slug(mac)}/device/deleteDevice.action", {
    teamId: team_id,
    deviceId: device_id
  })
end
download_certificate(certificate_id, type, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 603
def download_certificate(certificate_id, type, mac: false)
  { type: type, certificate_id: certificate_id }.each { |k, v| raise "#{k} must not be nil" if v.nil? }

  r = request(:get, "account/#{platform_slug(mac)}/certificate/downloadCertificateContent.action", {
    teamId: team_id,
    certificateId: certificate_id,
    type: type
  })
  a = parse_response(r)
  if r.success? && a.include?("Apple Inc")
    return a
  else
    raise UnexpectedResponse.new, "Couldn't download certificate, got this instead: #{a}"
  end
end
download_key(id: nil) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 775
def download_key(id: nil)
  response = request(:get, 'account/auth/key/download', { teamId: team_id, keyId: id })
  parse_response(response)
end
download_provisioning_profile(profile_id, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 706
def download_provisioning_profile(profile_id, mac: false)
  ensure_csrf(Spaceship::Portal::ProvisioningProfile) do
    fetch_csrf_token_for_provisioning
  end

  r = request(:get, "account/#{platform_slug(mac)}/profile/downloadProfileContent", {
    teamId: team_id,
    provisioningProfileId: profile_id
  })
  a = parse_response(r)
  if r.success? && a.include?("DOCTYPE plist PUBLIC")
    return a
  else
    raise UnexpectedResponse.new, "Couldn't download provisioning profile, got this instead: #{a}"
  end
end
enable_device!(device_id, device_udid, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 564
def enable_device!(device_id, device_udid, mac: false)
  req = request(:post, "https://developer.apple.com/services-account/#{PROTOCOL_VERSION}/account/#{platform_slug(mac)}/device/enableDevice.action", {
      teamId: team_id,
      displayId: device_id,
      deviceNumber: device_udid
  })
  parse_response(req, 'device')
end
get_key(id: nil) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 769
def get_key(id: nil)
  response = request(:post, 'account/auth/key/get', { teamId: team_id, keyId: id })
  # response contains a list of keys with 1 item
  parse_response(response, 'keys').first
end
in_house?() click to toggle source

Is the current session from an Enterprise In House account?

# File spaceship/lib/spaceship/portal/portal_client.rb, line 89
def in_house?
  return @in_house unless @in_house.nil?
  @in_house = (team_information['type'] == 'In-House')
end
list_keys() click to toggle source

@!group Keys

# File spaceship/lib/spaceship/portal/portal_client.rb, line 757
def list_keys
  paging do |page_number|
    response = request(:post, 'account/auth/key/list', {
      teamId: team_id,
      pageNumber: page_number,
      pageSize: page_size,
      sort: 'name=asc'
    })
    parse_response(response, 'keys')
  end
end
list_pending_agreements(language: "en") click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 103
def list_pending_agreements(language: "en")
  r = request(:post) do |req|
    req.url("account/listPendingAgreements")
    req.body = {
      teamId: team_id,
      languageIsoCode: language
    }.to_json
    req.headers['Content-Type'] = 'application/json'
  end

  return parse_response(r)
end
merchants(mac: false) click to toggle source

@!group Merchant

# File spaceship/lib/spaceship/portal/portal_client.rb, line 334
def merchants(mac: false)
  paging do |page_number|
    r = request(:post, "account/#{platform_slug(mac)}/identifiers/listOMCs.action", {
        teamId: team_id,
        pageNumber: page_number,
        pageSize: page_size,
        sort: 'name=asc'
    })
    parse_response(r, 'identifierList')
  end
end
passbooks() click to toggle source

@!group Passbook

# File spaceship/lib/spaceship/portal/portal_client.rb, line 260
def passbooks
  paging do |page_number|
    r = request(:post, "account/ios/identifiers/listPassTypeIds.action", {
      teamId: team_id,
      pageNumber: page_number,
      pageSize: page_size,
      sort: 'name=asc'
    })
    parse_response(r, 'passTypeIdList')
  end
end
provisioning_profile_details(provisioning_profile_id: nil, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 676
def provisioning_profile_details(provisioning_profile_id: nil, mac: false)
  r = request(:post, "account/#{platform_slug(mac)}/profile/getProvisioningProfile.action", {
    teamId: team_id,
    provisioningProfileId: provisioning_profile_id
  })
  parse_response(r, 'provisioningProfile')
end
provisioning_profiles(mac: false) click to toggle source

@!group Provisioning Profiles

# File spaceship/lib/spaceship/portal/portal_client.rb, line 634
def provisioning_profiles(mac: false)
  paging do |page_number|
    req = request(:post, "account/#{platform_slug(mac)}/profile/listProvisioningProfiles.action", {
      teamId: team_id,
      pageNumber: page_number,
      pageSize: page_size,
      sort: 'name=asc',
      includeInactiveProfiles: true,
      onlyCountLists: true
    })

    result = parse_response(req, 'provisioningProfiles')

    csrf_cache[Spaceship::Portal::ProvisioningProfile] = self.csrf_tokens

    result
  end
end
provisioning_profiles_via_xcode_api(mac: false) click to toggle source

this endpoint is used by Xcode to fetch provisioning profiles. The response is an xml plist but has the added benefit of containing the appId of each provisioning profile.

Use this method over `provisioning_profiles` if possible because no secondary API calls are necessary to populate the ProvisioningProfile data model.

# File spaceship/lib/spaceship/portal/portal_client.rb, line 658
def provisioning_profiles_via_xcode_api(mac: false)
  req = request(:post) do |r|
    r.url("https://developerservices2.apple.com/services/#{PROTOCOL_VERSION}/#{platform_slug(mac)}/listProvisioningProfiles.action")
    r.params = {
      teamId: team_id,
      includeInactiveProfiles: true,
      includeExpiredProfiles: true,
      onlyCountLists: true
    }
  end

  result = parse_response(req, 'provisioningProfiles')

  csrf_cache[Spaceship::Portal::ProvisioningProfile] = self.csrf_tokens

  result
end
repair_provisioning_profile!(profile_id, name, distribution_method, app_id, certificate_ids, device_ids, mac: false, sub_platform: nil, template_name: nil) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 732
def repair_provisioning_profile!(profile_id, name, distribution_method, app_id, certificate_ids, device_ids, mac: false, sub_platform: nil, template_name: nil)
  fetch_csrf_token_for_provisioning

  params = {
      teamId: team_id,
      provisioningProfileId: profile_id,
      provisioningProfileName: name,
      appIdId: app_id,
      distributionType: distribution_method,
      certificateIds: certificate_ids.join(','),
      deviceIds: device_ids
  }
  params[:subPlatform] = sub_platform if sub_platform
  # if `template_name` is nil, Default entitlements will be used
  params[:template] = template_name if template_name

  r = request(:post, "account/#{platform_slug(mac)}/profile/regenProvisioningProfile.action", params)

  parse_response(r, 'provisioningProfile')
end
revoke_certificate!(certificate_id, type, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 619
def revoke_certificate!(certificate_id, type, mac: false)
  ensure_csrf(Spaceship::Portal::Certificate)

  r = request(:post, "account/#{platform_slug(mac)}/certificate/revokeCertificate.action", {
    teamId: team_id,
    certificateId: certificate_id,
    type: type
  })
  parse_response(r, 'certRequests')
end
revoke_key!(id: nil) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 798
def revoke_key!(id: nil)
  fetch_csrf_token_for_keys
  response = request(:post, 'account/auth/key/revoke', { teamId: team_id, keyId: id })
  parse_response(response)
end
select_team(team_id: nil, team_name: nil) click to toggle source

Shows a team selection for the user in the terminal. This should not be called on CI systems

@param team_id (String) (optional): The ID of a Developer Portal team @param team_name (String) (optional): The name of a Developer Portal team

# File spaceship/lib/spaceship/portal/portal_client.rb, line 72
def select_team(team_id: nil, team_name: nil)
  @current_team_id = self.UI.select_team(team_id: team_id, team_name: team_name)
end
send_login_request(user, password) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 27
def send_login_request(user, password)
  response = send_shared_login_request(user, password)
  return response if self.cookie.include?("myacinfo")

  # When the user has 2 step enabled, we might have to call this method again
  # This only occurs when the user doesn't have a team on App Store Connect
  # For 2 step verification we use the App Store Connect back-end
  # which is enough to get the DES... cookie, however we don't get a valid
  # myacinfo cookie at that point. That means, after getting the DES... cookie
  # we have to send the login request again. This will then get us a valid myacinfo
  # cookie, additionally to the DES... cookie
  return send_shared_login_request(user, password)
end
team_id() click to toggle source

@return (String) The currently selected Team ID

# File spaceship/lib/spaceship/portal/portal_client.rb, line 54
def team_id
  return @current_team_id if @current_team_id

  if teams.count > 1
    puts("The current user is in #{teams.count} teams. Pass a team ID or call `select_team` to choose a team. Using the first one for now.")
  end

  if teams.count == 0
    raise "User '#{user}' does not have access to any teams with an active membership"
  end
  @current_team_id ||= teams[0]['teamId']
end
team_id=(team_id) click to toggle source

Set a new team ID which will be used from now on

# File spaceship/lib/spaceship/portal/portal_client.rb, line 77
def team_id=(team_id)
  @current_team_id = team_id
end
team_information() click to toggle source

@return (Hash) Fetches all information of the currently used team

# File spaceship/lib/spaceship/portal/portal_client.rb, line 82
def team_information
  teams.find do |t|
    t['teamId'] == team_id
  end
end
team_invite(email, role) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 487
def team_invite(email, role)
  ensure_csrf(Spaceship::Portal::Persons)
  response = request(:post) do |req|
    req.url("/services-account/#{PROTOCOL_VERSION}/account/sendInvites")
    req.body = {
      invites: [
        { recipientEmail: email, recipientRole: role }
      ],
      teamId: team_id
    }.to_json
    req.headers['Content-Type'] = 'application/json'
  end
  parse_response(response)
end
team_invited() click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 449
def team_invited
  response = request(:post) do |req|
    req.url("/services-account/#{PROTOCOL_VERSION}/account/getInvites")
    req.body = {
      teamId: team_id
    }.to_json
    req.headers['Content-Type'] = 'application/json'
  end
  parse_response(response)
end
team_members() click to toggle source

@!group Team

# File spaceship/lib/spaceship/portal/portal_client.rb, line 438
def team_members
  response = request(:post) do |req|
    req.url("/services-account/#{PROTOCOL_VERSION}/account/getTeamMembers")
    req.body = {
      teamId: team_id
    }.to_json
    req.headers['Content-Type'] = 'application/json'
  end
  parse_response(response)
end
team_remove_member!(team_member_id) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 474
def team_remove_member!(team_member_id)
  ensure_csrf(Spaceship::Portal::Persons)
  response = request(:post) do |req|
    req.url("/services-account/#{PROTOCOL_VERSION}/account/removeTeamMembers")
    req.body = {
      teamId: team_id,
      teamMemberIds: [team_member_id]
    }.to_json
    req.headers['Content-Type'] = 'application/json'
  end
  parse_response(response)
end
team_set_role(team_member_id, role) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 460
def team_set_role(team_member_id, role)
  ensure_csrf(Spaceship::Portal::Persons)
  response = request(:post) do |req|
    req.url("/services-account/#{PROTOCOL_VERSION}/account/setTeamMemberRoles")
    req.body = {
      teamId: team_id,
      role: role,
      teamMemberIds: [team_member_id]
    }.to_json
    req.headers['Content-Type'] = 'application/json'
  end
  parse_response(response)
end
teams() click to toggle source

@return (Array) A list of all available teams

# File spaceship/lib/spaceship/portal/portal_client.rb, line 42
def teams
  return @teams if @teams
  req = request(:post, "account/listTeams.action")
  @teams = parse_response(req, 'teams').sort_by do |team|
    [
      team['name'],
      team['teamId']
    ]
  end
end
update_app_name!(app_id, name, mac: false) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 245
def update_app_name!(app_id, name, mac: false)
  ensure_csrf(Spaceship::Portal::App)

  r = request(:post, "account/#{platform_slug(mac)}/identifiers/updateAppIdName.action", {
    teamId: team_id,
    appIdId: app_id,
    name: valid_name_for(name)
  })
  parse_response(r, 'appId')
end
update_service_for_app(app, service) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 140
def update_service_for_app(app, service)
  ensure_csrf(Spaceship::Portal::App)

  request(:post, service.service_uri, {
    teamId: team_id,
    displayId: app.app_id,
    featureType: service.service_id,
    featureValue: service.value
  })

  details_for_app(app)
end
valid_name_for(input) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 190
def valid_name_for(input)
  latinized = input.to_slug.transliterate
  latinized = latinized.gsub(/[^0-9A-Za-z\d\s]/, '') # remove non-valid characters
  # Check if the input string was modified, since it might be empty now
  # (if it only contained non-latin symbols) or the duplicate of another app
  if latinized != input
    latinized << " "
    latinized << Digest::MD5.hexdigest(input)
  end
  latinized
end
website_push(mac: false) click to toggle source

@!group Website Push

# File spaceship/lib/spaceship/portal/portal_client.rb, line 297
def website_push(mac: false)
  paging do |page_number|
    r = request(:post, "account/#{platform_slug(mac)}/identifiers/listWebsitePushIds.action", {
        teamId: team_id,
        pageNumber: page_number,
        pageSize: page_size,
        sort: 'name=asc'
    })
    parse_response(r, 'websitePushIdList')
  end
end

Private Instance Methods

csrf_cache() click to toggle source

This is a cache of entity type (App, AppGroup, Certificate, Device) to csrf_tokens

# File spaceship/lib/spaceship/portal/portal_client.rb, line 807
def csrf_cache
  @csrf_cache ||= {}
end
ensure_csrf(klass) { |: all| ... } click to toggle source

Ensures that there are csrf tokens for the appropriate entity type Relies on store_csrf_tokens to set csrf_tokens to the appropriate value then stores that in the correct place in cache This method also takes a block, if you want to send a custom request, instead of calling `.all` on the given klass. This is used for provisioning profiles.

# File spaceship/lib/spaceship/portal/portal_client.rb, line 816
def ensure_csrf(klass)
  if csrf_cache[klass]
    self.csrf_tokens = csrf_cache[klass]
    return
  end

  self.csrf_tokens = nil

  # If we directly create a new resource (e.g. app) without querying anything before
  # we don't have a valid csrf token, that's why we have to do at least one request
  block_given? ? yield : klass.all

  csrf_cache[klass] = self.csrf_tokens
end
fetch_csrf_token_for_keys() click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 849
def fetch_csrf_token_for_keys
  response = request(:post, 'account/auth/key/list', {
     teamId: team_id,
     pageNumber: 1,
     pageSize: 1,
     sort: 'name=asc'
   })

  parse_response(response, 'keys')
  return nil
end
fetch_csrf_token_for_provisioning(mac: false) click to toggle source

We need a custom way to fetch the csrf token for the provisioning profile requests, since we use a separate API endpoint (host of Xcode API) to fetch the provisioning profiles All we do is fetch one profile (if exists) to get a valid csrf token with its time stamp This method is being called from all requests that modify, create or downloading provisioning profiles. Source github.com/fastlane/fastlane/issues/5903

# File spaceship/lib/spaceship/portal/portal_client.rb, line 837
def fetch_csrf_token_for_provisioning(mac: false)
  response = request(:post, "account/#{platform_slug(mac)}/profile/listProvisioningProfiles.action", {
     teamId: team_id,
     pageNumber: 1,
     pageSize: 1,
     sort: 'name=asc'
   })

  parse_response(response, 'provisioningProfiles')
  return nil
end
platform_slug(mac) click to toggle source
# File spaceship/lib/spaceship/portal/portal_client.rb, line 94
def platform_slug(mac)
  if mac
    'mac'
  else
    'ios'
  end
end