diff --git a/spaceship/lib/spaceship/connect_api.rb b/spaceship/lib/spaceship/connect_api.rb index 86f6af7ae81..bada9958b35 100644 --- a/spaceship/lib/spaceship/connect_api.rb +++ b/spaceship/lib/spaceship/connect_api.rb @@ -38,6 +38,8 @@ require 'spaceship/connect_api/models/custom_app_user' require 'spaceship/connect_api/models/pre_release_version' +require 'spaceship/connect_api/models/app_availability' +require 'spaceship/connect_api/models/territory_availability' require 'spaceship/connect_api/models/app_data_usage' require 'spaceship/connect_api/models/app_data_usage_category' require 'spaceship/connect_api/models/app_data_usage_data_protection' diff --git a/spaceship/lib/spaceship/connect_api/models/app.rb b/spaceship/lib/spaceship/connect_api/models/app.rb index cc0b6da0fc2..1c23b74b9c1 100644 --- a/spaceship/lib/spaceship/connect_api/models/app.rb +++ b/spaceship/lib/spaceship/connect_api/models/app.rb @@ -148,6 +148,16 @@ def fetch_latest_app_info(client: nil, includes: Spaceship::ConnectAPI::AppInfo: return resp.to_models.first end + # + # App Availabilities + # + + def get_app_availabilities(client: nil, filter: {}, includes: "territoryAvailabilities", limit: { "territoryAvailabilities": 200 }) + client ||= Spaceship::ConnectAPI + resp = client.get_app_availabilities(app_id: id, filter: filter, includes: includes, limit: limit, sort: nil) + return resp.to_models.first + end + # # Available Territories # diff --git a/spaceship/lib/spaceship/connect_api/models/app_availability.rb b/spaceship/lib/spaceship/connect_api/models/app_availability.rb new file mode 100644 index 00000000000..542d152abbd --- /dev/null +++ b/spaceship/lib/spaceship/connect_api/models/app_availability.rb @@ -0,0 +1,23 @@ +require_relative '../model' +module Spaceship + class ConnectAPI + class AppAvailability + include Spaceship::ConnectAPI::Model + + attr_accessor :app + attr_accessor :available_in_new_territories + + attr_accessor :territoryAvailabilities + + attr_mapping({ + app: 'app', + availableInNewTerritories: 'available_in_new_territories', + territoryAvailabilities: 'territory_availabilities' + }) + + def self.type + return 'appAvailabilities' + end + end + end +end diff --git a/spaceship/lib/spaceship/connect_api/models/territory_availability.rb b/spaceship/lib/spaceship/connect_api/models/territory_availability.rb new file mode 100644 index 00000000000..aa0d96eb7e3 --- /dev/null +++ b/spaceship/lib/spaceship/connect_api/models/territory_availability.rb @@ -0,0 +1,62 @@ +require_relative '../model' +module Spaceship + class ConnectAPI + class TerritoryAvailability + include Spaceship::ConnectAPI::Model + + attr_accessor :available + attr_accessor :content_statuses + attr_accessor :pre_order_enabled + attr_accessor :pre_order_publish_date + attr_accessor :release_date + + module ContentStatus + AVAILABLE = "AVAILABLE" + AVAILABLE_FOR_PREORDER_ON_DATE = "AVAILABLE_FOR_PREORDER_ON_DATE" + PROCESSING_TO_NOT_AVAILABLE = "PROCESSING_TO_NOT_AVAILABLE" + PROCESSING_TO_AVAILABLE = "PROCESSING_TO_AVAILABLE" + PROCESSING_TO_PRE_ORDER = "PROCESSING_TO_PRE_ORDER" + AVAILABLE_FOR_SALE_UNRELEASED_APP = "AVAILABLE_FOR_SALE_UNRELEASED_APP" + PREORDER_ON_UNRELEASED_APP = "PREORDER_ON_UNRELEASED_APP" + AVAILABLE_FOR_PREORDER = "AVAILABLE_FOR_PREORDER" + MISSING_RATING = "MISSING_RATING" + CANNOT_SELL_RESTRICTED_RATING = "CANNOT_SELL_RESTRICTED_RATING" + BRAZIL_REQUIRED_TAX_ID = "BRAZIL_REQUIRED_TAX_ID" + MISSING_GRN = "MISSING_GRN" + UNVERIFIED_GRN = "UNVERIFIED_GRN" + CANNOT_SELL_SEVENTEEN_PLUS_APPS = "CANNOT_SELL_SEVENTEEN_PLUS_APPS" + CANNOT_SELL_SEXUALLY_EXPLICIT = "CANNOT_SELL_SEXUALLY_EXPLICIT" + CANNOT_SELL_NON_IOS_GAMES = "CANNOT_SELL_NON_IOS_GAMES" + CANNOT_SELL_SEVENTEEN_PLUS_GAMES = "CANNOT_SELL_SEVENTEEN_PLUS_GAMES" + CANNOT_SELL_FREQUENT_INTENSE_GAMBLING = "CANNOT_SELL_FREQUENT_INTENSE_GAMBLING" + CANNOT_SELL_CASINO = "CANNOT_SELL_CASINO" + CANNOT_SELL_CASINO_WITHOUT_GRAC = "CANNOT_SELL_CASINO_WITHOUT_GRAC" + CANNOT_SELL_CASINO_WITHOUT_AGE_VERIFICATION = "CANNOT_SELL_CASINO_WITHOUT_AGE_VERIFICATION" + CANNOT_SELL_FREQUENT_INTENSE_ALCOHOL_TOBACCO_DRUGS = "CANNOT_SELL_FREQUENT_INTENSE_ALCOHOL_TOBACCO_DRUGS" + CANNOT_SELL_FREQUENT_INTENSE_VIOLENCE = "CANNOT_SELL_FREQUENT_INTENSE_VIOLENCE" + CANNOT_SELL_FREQUENT_INTENSE_SEXUAL_CONTENT_NUDITY = "CANNOT_SELL_FREQUENT_INTENSE_SEXUAL_CONTENT_NUDITY" + CANNOT_SELL_INFREQUENT_MILD_ALCOHOL_TOBACCO_DRUGS = "CANNOT_SELL_INFREQUENT_MILD_ALCOHOL_TOBACCO_DRUGS" + CANNOT_SELL_INFREQUENT_MILD_SEXUAL_CONTENT_NUDITY = "CANNOT_SELL_INFREQUENT_MILD_SEXUAL_CONTENT_NUDITY" + CANNOT_SELL_ADULT_ONLY = "CANNOT_SELL_ADULT_ONLY" + CANNOT_SELL_FREQUENT_INTENSE = "CANNOT_SELL_FREQUENT_INTENSE" + CANNOT_SELL_FREQUENT_INTENSE_WITHOUT_GRAC = "CANNOT_SELL_FREQUENT_INTENSE_WITHOUT_GRAC" + CANNOT_SELL_GAMBLING_CONTESTS = "CANNOT_SELL_GAMBLING_CONTESTS" + CANNOT_SELL_GAMBLING = "CANNOT_SELL_GAMBLING" + CANNOT_SELL_CONTESTS = "CANNOT_SELL_CONTESTS" + CANNOT_SELL = "CANNOT_SELL" + end + + attr_mapping({ + available: 'available', + contentStatuses: 'content_statuses', + preOrderEnabled: 'pre_order_enabled', + preOrderPublishDate: 'pre_order_publish_date', + releaseDate: 'release_date' + }) + + def self.type + return 'territoryAvailabilities' + end + end + end +end diff --git a/spaceship/lib/spaceship/connect_api/tunes/tunes.rb b/spaceship/lib/spaceship/connect_api/tunes/tunes.rb index aabc797c3ca..d3f9a4623b0 100644 --- a/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +++ b/spaceship/lib/spaceship/connect_api/tunes/tunes.rb @@ -416,6 +416,15 @@ def patch_app_preview_set_previews(app_preview_set_id: nil, app_preview_ids: nil tunes_request_client.patch("#{Version::V1}/appPreviewSets/#{app_preview_set_id}/relationships/appPreviews", body) end + # + # appAvailabilities + # + + def get_app_availabilities(app_id: nil, filter: nil, includes: nil, limit: nil, sort: nil) + params = tunes_request_client.build_params(filter: nil, includes: includes, limit: limit, sort: nil) + tunes_request_client.get("#{Version::V2}/appAvailabilities/#{app_id}", params) + end + # # availableTerritories # diff --git a/spaceship/spec/connect_api/fixtures/tunes/app_availabilities_ready_for_distribution.json b/spaceship/spec/connect_api/fixtures/tunes/app_availabilities_ready_for_distribution.json new file mode 100644 index 00000000000..7da106dad52 --- /dev/null +++ b/spaceship/spec/connect_api/fixtures/tunes/app_availabilities_ready_for_distribution.json @@ -0,0 +1,73 @@ +{ + "data": { + "type": "appAvailabilities", + "id": "123456789", + "attributes": { + "availableInNewTerritories": false + }, + "relationships": { + "territoryAvailabilities": { + "meta": { + "paging": { + "total": 175, + "limit": 200 + } + }, + "data": [ + { + "type": "territoryAvailabilities", + "id": "abcdefg" + }, + { + "type": "territoryAvailabilities", + "id": "hijklmn" + } + ], + "links": { + "self": "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789/relationships/territoryAvailabilities", + "related": "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789/territoryAvailabilities" + } + } + }, + "links": { + "self": "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789" + } + }, + "included": [ + { + "type": "territoryAvailabilities", + "id": "abcdefg", + "attributes": { + "available": true, + "availableInPast": true, + "preOrderAvailableInPast": false, + "releaseDate": "2024-02-26", + "preOrderEnabled": false, + "preOrderPublishDate": null, + "contentStatuses": ["AVAILABLE"] + }, + "links": { + "self": "https://appstoreconnect.apple.com/iris/v1/territoryAvailabilities/abcdefg" + } + }, + { + "type": "territoryAvailabilities", + "id": "hijklmn", + "attributes": { + "available": true, + "availableInPast": true, + "preOrderAvailableInPast": false, + "releaseDate": "2024-02-26", + "preOrderEnabled": false, + "preOrderPublishDate": null, + "contentStatuses": ["AVAILABLE"] + }, + "links": { + "self": "https://appstoreconnect.apple.com/iris/v1/territoryAvailabilities/hijklmn" + } + } + ], + "links": { + "self": "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789?include=territoryAvailabilities" + } +} diff --git a/spaceship/spec/connect_api/fixtures/tunes/app_availabilities_removed_app.json b/spaceship/spec/connect_api/fixtures/tunes/app_availabilities_removed_app.json new file mode 100644 index 00000000000..a79ed8f94cb --- /dev/null +++ b/spaceship/spec/connect_api/fixtures/tunes/app_availabilities_removed_app.json @@ -0,0 +1,73 @@ +{ + "data": { + "type": "appAvailabilities", + "id": "123456789", + "attributes": { + "availableInNewTerritories": false + }, + "relationships": { + "territoryAvailabilities": { + "meta": { + "paging": { + "total": 175, + "limit": 200 + } + }, + "data": [ + { + "type": "territoryAvailabilities", + "id": "abcdefg" + }, + { + "type": "territoryAvailabilities", + "id": "hijklmn" + } + ], + "links": { + "self": "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789/relationships/territoryAvailabilities", + "related": "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789/territoryAvailabilities" + } + } + }, + "links": { + "self": "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789" + } + }, + "included": [ + { + "type": "territoryAvailabilities", + "id": "abcdefg", + "attributes": { + "available": false, + "availableInPast": true, + "preOrderAvailableInPast": false, + "releaseDate": "2024-02-26", + "preOrderEnabled": false, + "preOrderPublishDate": null, + "contentStatuses": ["CANNOT_SELL"] + }, + "links": { + "self": "https://appstoreconnect.apple.com/iris/v1/territoryAvailabilities/abcdefg" + } + }, + { + "type": "territoryAvailabilities", + "id": "hijklmn", + "attributes": { + "available": false, + "availableInPast": true, + "preOrderAvailableInPast": false, + "releaseDate": "2024-02-26", + "preOrderEnabled": false, + "preOrderPublishDate": null, + "contentStatuses": ["CANNOT_SELL"] + }, + "links": { + "self": "https://appstoreconnect.apple.com/iris/v1/territoryAvailabilities/hijklmn" + } + } + ], + "links": { + "self": "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789?include=territoryAvailabilities" + } +} diff --git a/spaceship/spec/connect_api/models/app_spec.rb b/spaceship/spec/connect_api/models/app_spec.rb index ffe4a0fb457..ef0327bd055 100644 --- a/spaceship/spec/connect_api/models/app_spec.rb +++ b/spaceship/spec/connect_api/models/app_spec.rb @@ -157,4 +157,34 @@ expect(review_submission.state).to eq(Spaceship::ConnectAPI::ReviewSubmission::ReviewSubmissionState::READY_FOR_REVIEW) end end + + describe("#get_app_availabilities") do + it('gets app availabilities when app is ready for distribution') do + ConnectAPIStubbing::Tunes.stub_get_app_availabilities_ready_for_distribution + app = Spaceship::ConnectAPI::App.new("123456789", []) + + availabilities = app.get_app_availabilities + + expect(availabilities.availableInNewTerritories).to be(false) + expect(availabilities.territory_availabilities.count).to eq(2) + expect(availabilities.territory_availabilities[0].available).to be(true) + expect(availabilities.territory_availabilities[1].available).to be(true) + expect(availabilities.territory_availabilities[0].contentStatuses).to eq(["AVAILABLE"]) + expect(availabilities.territory_availabilities[1].contentStatuses).to eq(["AVAILABLE"]) + end + + it('gets app availabilities when app is removed from sale') do + ConnectAPIStubbing::Tunes.stub_get_app_availabilities_removed_from_sale + app = Spaceship::ConnectAPI::App.new("123456789", []) + + availabilities = app.get_app_availabilities + + expect(availabilities.availableInNewTerritories).to be(false) + expect(availabilities.territory_availabilities.count).to eq(2) + expect(availabilities.territory_availabilities[0].available).to be(false) + expect(availabilities.territory_availabilities[1].available).to be(false) + expect(availabilities.territory_availabilities[0].contentStatuses).to eq(["CANNOT_SELL"]) + expect(availabilities.territory_availabilities[1].contentStatuses).to eq(["CANNOT_SELL"]) + end + end end diff --git a/spaceship/spec/connect_api/tunes/tunes_client_spec.rb b/spaceship/spec/connect_api/tunes/tunes_client_spec.rb index 66d797d7b1c..c143e140fbf 100644 --- a/spaceship/spec/connect_api/tunes/tunes_client_spec.rb +++ b/spaceship/spec/connect_api/tunes/tunes_client_spec.rb @@ -45,6 +45,24 @@ def test_request_body(url, body) return req_mock end + describe "appAvailabilities" do + context 'get_app_availabilities' do + let(:path) { "v2/appAvailabilities" } + let(:app_id) { "123" } + + it 'succeeds' do + url = "#{path}/#{app_id}" + params = { + include: "territoryAvailabilities", + limit: { "territoryAvailabilities": 200 } + } + req_mock = test_request_params(url, params) + expect(client).to receive(:request).with(:get).and_yield(req_mock).and_return(req_mock) + client.get_app_availabilities(app_id: app_id, includes: "territoryAvailabilities", limit: { "territoryAvailabilities": 200 }) + end + end + end + describe "appStoreVersionReleaseRequests" do context 'post_app_store_version_release_request' do let(:path) { "v1/appStoreVersionReleaseRequests" } diff --git a/spaceship/spec/connect_api/tunes/tunes_stubbing.rb b/spaceship/spec/connect_api/tunes/tunes_stubbing.rb index 746ba06a196..8a060292a31 100644 --- a/spaceship/spec/connect_api/tunes/tunes_stubbing.rb +++ b/spaceship/spec/connect_api/tunes/tunes_stubbing.rb @@ -14,6 +14,16 @@ def stub_request(*args) WebMock::API.stub_request(*args) end + def stub_get_app_availabilities_ready_for_distribution + stub_request(:get, "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789?include=territoryAvailabilities&limit%5BterritoryAvailabilities%5D=200"). + to_return(status: 200, body: read_fixture_file('app_availabilities_ready_for_distribution.json'), headers: { 'Content-Type' => 'application/json' }) + end + + def stub_get_app_availabilities_removed_from_sale + stub_request(:get, "https://appstoreconnect.apple.com/iris/v2/appAvailabilities/123456789?include=territoryAvailabilities&limit%5BterritoryAvailabilities%5D=200"). + to_return(status: 200, body: read_fixture_file('app_availabilities_removed_app.json'), headers: { 'Content-Type' => 'application/json' }) + end + def stub_get_app_infos stub_request(:get, "https://appstoreconnect.apple.com/iris/v1/apps/123456789/appInfos"). to_return(status: 200, body: read_fixture_file('app_infos.json'), headers: { 'Content-Type' => 'application/json' })