Commit 9183784e authored by Ben Blake's avatar Ben Blake Committed by Commit Bot

Create AutofillOfferManagerFactory and implement GetOfferDataRequest.

This change further implements the functionality of AutofillOfferManager. AutofillManager now accesses a singleton AutofillOfferManager via the AutofillOfferManagerFactory. AutofillOfferManager then prepares a request which is sent to the PaymentsClient to retrieve offer data. In further CLs, the data retrieved during these calls will stored and used.

Change-Id: I384c95f26b9b3094d9b3387d467134ef5998396e
Bug: 1093057
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2258154
Commit-Queue: Ben Blake <fiorito@google.com>
Reviewed-by: default avatarAnne Lim <annelim@google.com>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarJared Saul <jsaul@google.com>
Reviewed-by: default avatarSiyu An <siyua@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798344}
parent 2d174628
......@@ -143,6 +143,8 @@ static_library("browser") {
"autofill/autocomplete_history_manager_factory.h",
"autofill/autofill_gstatic_reader.cc",
"autofill/autofill_gstatic_reader.h",
"autofill/autofill_offer_manager_factory.cc",
"autofill/autofill_offer_manager_factory.h",
"autofill/autofill_profile_validator_factory.cc",
"autofill/autofill_profile_validator_factory.h",
"autofill/personal_data_manager_factory.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/autofill/autofill_offer_manager_factory.h"
#include "base/memory/singleton.h"
#include "chrome/browser/profiles/profile.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
namespace autofill {
namespace payments {
// static
AutofillOfferManager* AutofillOfferManagerFactory::GetForProfile(
Profile* profile) {
return static_cast<AutofillOfferManager*>(
GetInstance()->GetServiceForBrowserContext(profile, true));
}
// static
AutofillOfferManagerFactory* AutofillOfferManagerFactory::GetInstance() {
return base::Singleton<AutofillOfferManagerFactory>::get();
}
AutofillOfferManagerFactory::AutofillOfferManagerFactory()
: BrowserContextKeyedServiceFactory(
"AutofillOfferManager",
BrowserContextDependencyManager::GetInstance()) {}
AutofillOfferManagerFactory::~AutofillOfferManagerFactory() = default;
KeyedService* AutofillOfferManagerFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new AutofillOfferManager();
}
} // namespace payments
} // namespace autofill
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
#include "base/compiler_specific.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/keyed_service/core/keyed_service.h"
namespace base {
template <typename T>
struct DefaultSingletonTraits;
}
class Profile;
namespace autofill {
namespace payments {
class AutofillOfferManager;
// Singleton that owns all AutofillOfferManager and associates them with
// Profiles.
class AutofillOfferManagerFactory : public BrowserContextKeyedServiceFactory {
public:
AutofillOfferManagerFactory(const AutofillOfferManagerFactory&) = delete;
AutofillOfferManagerFactory& operator=(const AutofillOfferManagerFactory&) =
delete;
static AutofillOfferManager* GetForProfile(Profile* profile);
static AutofillOfferManagerFactory* GetInstance();
private:
friend struct base::DefaultSingletonTraits<AutofillOfferManagerFactory>;
AutofillOfferManagerFactory();
~AutofillOfferManagerFactory() override;
// BrowserContextKeyedServiceFactory:
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const override;
};
} // namespace payments
} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
......@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/autofill/address_normalizer_factory.h"
#include "chrome/browser/autofill/autocomplete_history_manager_factory.h"
#include "chrome/browser/autofill/autofill_offer_manager_factory.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/autofill/risk_util.h"
#include "chrome/browser/autofill/strike_database_factory.h"
......@@ -178,6 +179,13 @@ AddressNormalizer* ChromeAutofillClient::GetAddressNormalizer() {
return nullptr;
}
payments::AutofillOfferManager*
ChromeAutofillClient::GetAutofillOfferManager() {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
return payments::AutofillOfferManagerFactory::GetForProfile(profile);
}
const GURL& ChromeAutofillClient::GetLastCommittedURL() {
return web_contents()->GetLastCommittedURL();
}
......
......@@ -63,6 +63,7 @@ class ChromeAutofillClient
ukm::UkmRecorder* GetUkmRecorder() override;
ukm::SourceId GetUkmSourceId() override;
AddressNormalizer* GetAddressNormalizer() override;
payments::AutofillOfferManager* GetAutofillOfferManager() override;
const GURL& GetLastCommittedURL() override;
security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override;
std::string GetPageLanguage() const override;
......
......@@ -83,6 +83,8 @@ static_library("browser") {
"data_model/autofill_data_model.h",
"data_model/autofill_metadata.cc",
"data_model/autofill_metadata.h",
"data_model/autofill_offer_data.cc",
"data_model/autofill_offer_data.h",
"data_model/autofill_profile.cc",
"data_model/autofill_profile.h",
"data_model/autofill_profile_comparator.cc",
......@@ -608,6 +610,7 @@ source_set("unit_tests") {
"logging/log_buffer_submitter_unittest.cc",
"logging/log_manager_unittest.cc",
"logging/log_router_unittest.cc",
"payments/autofill_offer_manager_unittest.cc",
"payments/credit_card_access_manager_unittest.cc",
"payments/credit_card_cvc_authenticator_unittest.cc",
"payments/credit_card_save_manager_unittest.cc",
......
......@@ -35,6 +35,10 @@ version_info::Channel AutofillClient::GetChannel() const {
return version_info::Channel::UNKNOWN;
}
payments::AutofillOfferManager* AutofillClient::GetAutofillOfferManager() {
return nullptr;
}
std::string AutofillClient::GetPageLanguage() const {
return std::string();
}
......
......@@ -72,6 +72,7 @@ enum class WebauthnDialogState;
struct Suggestion;
namespace payments {
class AutofillOfferManager;
class PaymentsClient;
}
......@@ -274,6 +275,9 @@ class AutofillClient : public RiskDataLoader {
// Gets an AddressNormalizer instance (can be null).
virtual AddressNormalizer* GetAddressNormalizer() = 0;
// Gets an AutofillOfferManager instance.
virtual payments::AutofillOfferManager* GetAutofillOfferManager();
// Gets the virtual URL of the last committed page of this client's
// associated WebContents.
virtual const GURL& GetLastCommittedURL() = 0;
......
......@@ -60,6 +60,7 @@
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
......@@ -1657,6 +1658,12 @@ AutofillManager::AutofillManager(
driver, this, GetAPIKeyForUrl(channel), client_->GetLogManager()));
}
CountryNames::SetLocaleString(app_locale_);
if (base::FeatureList::IsEnabled(
features::kAutofillEnableOffersInDownstream)) {
offer_manager_ = client_->GetAutofillOfferManager();
if (offer_manager_)
offer_manager_->Init(client_, app_locale_);
}
}
bool AutofillManager::RefreshDataModels() {
......
......@@ -32,6 +32,7 @@
#include "components/autofill/core/browser/form_types.h"
#include "components/autofill/core/browser/metrics/address_form_event_logger.h"
#include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/card_unmask_delegate.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/payments/full_card_request.h"
......@@ -673,6 +674,10 @@ class AutofillManager : public AutofillHandler,
// The credit card access manager, used to access local and server cards.
std::unique_ptr<CreditCardAccessManager> credit_card_access_manager_;
// The autofill offer manager, used to to retrieve offers for card
// suggestions.
payments::AutofillOfferManager* offer_manager_;
// Collected information about the autofill form where a credit card will be
// filled.
AutofillDriver::RendererFormDataAction credit_card_action_;
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
namespace autofill {
namespace payments {
AutofillOfferData::AutofillOfferData() = default;
AutofillOfferData::~AutofillOfferData() = default;
AutofillOfferData::AutofillOfferData(const AutofillOfferData&) = default;
AutofillOfferData& AutofillOfferData::operator=(const AutofillOfferData&) =
default;
} // namespace payments
} // namespace autofill
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_OFFER_DATA_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_OFFER_DATA_H_
#include <string>
#include <vector>
#include "base/strings/string16.h"
#include "url/gurl.h"
namespace autofill {
namespace payments {
// Represents an offer for certain merchants redeemable with certain cards.
struct AutofillOfferData {
public:
AutofillOfferData();
~AutofillOfferData();
AutofillOfferData(const AutofillOfferData&);
AutofillOfferData& operator=(const AutofillOfferData&);
// The unique server id of this offer.
std::string offer_id;
// The name of this offer.
base::string16 name;
// The description of this offer.
base::string16 description;
// The expiration timestamp of this offer, in the form of seconds since Unix
// epoch.
int64_t expiry;
// The merchant URL where this offer can be redeemed.
GURL merchant_domain;
// The ids of the cards this offer can be applied to.
std::vector<std::string> eligible_instrument_id;
// The legacy ids of the cards this offer can be applied to.
std::vector<std::string> eligible_legacy_instrument_id;
};
} // namespace payments
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_OFFER_DATA_H_
......@@ -4,10 +4,54 @@
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "base/bind.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "url/gurl.h"
namespace autofill {
namespace payments {
AutofillOfferManager::AutofillOfferManager() = default;
AutofillOfferManager::~AutofillOfferManager() = default;
} // namespace autofill
\ No newline at end of file
void AutofillOfferManager::Init(AutofillClient* client,
const std::string& app_locale) {
if (base::TimeDelta(AutofillClock::Now() - last_updated_timestamp_) >=
base::TimeDelta::FromMicroseconds(kOfferDataExpiryTimeInMicros) &&
!request_is_active_) {
client->GetPaymentsClient()->GetOfferData(
app_locale, base::BindOnce(&AutofillOfferManager::OnDidGetOfferData,
weak_ptr_factory_.GetWeakPtr()));
request_is_active_ = true;
request_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMicroseconds(kRequestExpiryTimeInMicros), this,
&AutofillOfferManager::OnRequestTimeout);
}
}
void AutofillOfferManager::OnRequestTimeout() {
request_is_active_ = false;
}
void AutofillOfferManager::OnDidGetOfferData(
AutofillClient::PaymentsRpcResult result,
const std::vector<AutofillOfferData>& offers) {
request_timer_.Stop();
request_is_active_ = false;
if (result == AutofillClient::SUCCESS) {
// TODO(crbug/1093057): Parse and store returned offer data.
last_updated_timestamp_ = AutofillClock::Now();
}
}
} // namespace payments
} // namespace autofill
......@@ -5,38 +5,78 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
#include <stdint.h>
#include <string>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/keyed_service/core/keyed_service.h"
// Constant used to set intervals between calls for new offer data.
static const int64_t kOfferDataExpiryTimeInMicros =
int64_t{1000000 * 60 * 60 * 24}; // 24 hours
// Constant used to set expiry time for a single call before the next call can
// be made.
static const int64_t kRequestExpiryTimeInMicros =
int64_t{1000000 * 60}; // 1 minute
namespace autofill {
struct AutofillOfferData {
AutofillOfferData();
~AutofillOfferData();
// The description of this offer.
base::string16 description;
// The name of this offer.
base::string16 name;
// The unique server id of this offer.
std::string offer_id;
// The ids of the cards this offer can be applied to.
std::vector<std::string> eligible_card_id;
// The merchant URL where this offer can be redeemed.
std::vector<std::string> merchant_domain;
};
class AutofillClient;
namespace payments {
// Manages all Autofill related offers. One per frame; owned by the
// AutofillManager.
class AutofillOfferManager {
class AutofillOfferManager : public KeyedService {
public:
AutofillOfferManager();
virtual ~AutofillOfferManager();
~AutofillOfferManager() override;
AutofillOfferManager(const AutofillOfferManager&) = delete;
AutofillOfferManager& operator=(const AutofillOfferManager&) = delete;
void Init(AutofillClient* client, const std::string& app_locale);
private:
// Helper function used as callback when using |request_timer_|
void OnRequestTimeout();
// Callback function after successfully retrieving offer data.
void OnDidGetOfferData(AutofillClient::PaymentsRpcResult result,
const std::vector<AutofillOfferData>& offers);
// The time the offer data was last retrieved from Payments.
base::Time last_updated_timestamp_;
// Bool used to track if a request has been sent.
bool request_is_active_ = false;
// Timer used to wait for sent requests to come back before sending another.
base::OneShotTimer request_timer_;
base::WeakPtrFactory<AutofillOfferManager> weak_ptr_factory_{this};
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest, InitFirstCallSucceeds);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitBeforeOfferDataExpiry_OneSecond);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitAfterOfferDataExpiry_OneSecond);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitBeforeTimerExpiry_OneSecond);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitAfterTimerExpiry_OneSecond);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitAfterOfferDataExpiryButRequestActive);
};
} // namespace payments
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
\ No newline at end of file
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/bind.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
static const char kTestAppLocale[] = "en";
static const int64_t kOneSecondMicros = 1000000;
namespace autofill {
namespace payments {
class AutofillOfferManagerTest : public testing::Test {
public:
AutofillOfferManagerTest() = default;
~AutofillOfferManagerTest() override = default;
void SetUp() override {
payments_client_ = new TestPaymentsClient(
autofill_driver_.GetURLLoaderFactory(),
autofill_client_.GetIdentityManager(), &personal_data_manager_);
autofill_client_.set_test_payments_client(
std::unique_ptr<TestPaymentsClient>(payments_client_));
}
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
TestAutofillClient autofill_client_;
TestAutofillDriver autofill_driver_;
TestPersonalDataManager personal_data_manager_;
TestPaymentsClient* payments_client_;
AutofillOfferManager autofill_offer_manager_;
};
TEST_F(AutofillOfferManagerTest, InitFirstCallSucceeds) {
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should call GetOfferData, as this is the first time Init() has been called
// and the |last_updated_timestamp| has not been set.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
}
TEST_F(AutofillOfferManagerTest, InitBeforeOfferDataExpiry_OneSecond) {
autofill_offer_manager_.last_updated_timestamp_ = AutofillClock::Now();
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kOfferDataExpiryTimeInMicros - kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should not call GetOfferData because it hasn't been long enough since the
// last successful request.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 0);
}
TEST_F(AutofillOfferManagerTest, InitAfterOfferDataExpiry_OneSecond) {
autofill_offer_manager_.last_updated_timestamp_ = AutofillClock::Now();
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kOfferDataExpiryTimeInMicros + kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should call GetOfferData because it has been long enough since the last
// successful request.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
}
TEST_F(AutofillOfferManagerTest, InitBeforeTimerExpiry_OneSecond) {
payments_client_->SetShouldReturnOfferData(false);
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kRequestExpiryTimeInMicros - kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should not call GetOfferData a second time because even though the request
// has not returned, it also has not expired.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
}
TEST_F(AutofillOfferManagerTest, InitAfterTimerExpiry_OneSecond) {
payments_client_->SetShouldReturnOfferData(false);
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kRequestExpiryTimeInMicros + kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should call GetOfferData a second time because even though the request has
// not returned, it has expired.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 2);
}
TEST_F(AutofillOfferManagerTest, InitAfterOfferDataExpiryButRequestActive) {
payments_client_->SetShouldReturnOfferData(false);
autofill_offer_manager_.last_updated_timestamp_ = AutofillClock::Now();
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kOfferDataExpiryTimeInMicros + kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should call GetOfferData because the offer data has expired.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kRequestExpiryTimeInMicros - kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should not call GetOfferData a second time because even though the request
// has not returned, it has not expired.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
}
} // namespace payments
} // namespace autofill
......@@ -25,8 +25,10 @@
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_data_model.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/account_info_getter.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
#include "components/autofill/core/browser/payments/payments_request.h"
#include "components/autofill/core/browser/payments/payments_service_url.h"
......@@ -82,6 +84,9 @@ const char kMigrateCardsRequestPath[] =
const char kMigrateCardsRequestFormat[] =
"requestContentType=application/json; charset=utf-8&request=%s";
const char kGetOfferDataRequestPath[] =
"payments/apis/chromepaymentsservice/getoffers";
const char kTokenFetchId[] = "wallet_client";
const char kPaymentsOAuth2Scope[] =
"https://www.googleapis.com/auth/wallet.chrome";
......@@ -1008,6 +1013,109 @@ class MigrateCardsRequest : public PaymentsRequest {
DISALLOW_COPY_AND_ASSIGN(MigrateCardsRequest);
};
class GetOfferDataRequest : public PaymentsRequest {
public:
GetOfferDataRequest(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback)
: app_locale_(app_locale), callback_(std::move(callback)) {}
~GetOfferDataRequest() override = default;
GetOfferDataRequest(const GetOfferDataRequest& other) = delete;
GetOfferDataRequest& operator=(const GetOfferDataRequest& other) = delete;
std::string GetRequestUrlPath() override { return kGetOfferDataRequestPath; }
std::string GetRequestContentType() override { return "application/json"; }
std::string GetRequestContent() override {
base::Value request_dict(base::Value::Type::DICTIONARY);
base::Value context(base::Value::Type::DICTIONARY);
context.SetKey("language_code", base::Value(app_locale_));
request_dict.SetKey("context", std::move(context));
std::string request_content;
base::JSONWriter::Write(request_dict, &request_content);
VLOG(3) << "getoffers request body: " << request_content;
return request_content;
}
void ParseResponse(const base::Value& response) override {
const auto* found_list =
response.FindKeyOfType("offer", base::Value::Type::LIST);
if (!found_list)
return;
std::vector<AutofillOfferData> offers;
for (const base::Value& result : found_list->GetList()) {
AutofillOfferData offer_data;
if (!result.is_dict() || !JsonToAutofillOfferData(result, offer_data))
continue;
offers.push_back(offer_data);
}
offers_.emplace(offers);
}
bool IsResponseComplete() override { return offers_.has_value(); }
void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override {
std::move(callback_).Run(result, std::move(offers_.value()));
}
private:
// Extract, validate, and assign all required fields.
bool JsonToAutofillOfferData(const base::Value& value,
AutofillOfferData& result) {
const std::string* offer_id = value.FindStringKey("offer_id");
if (!offer_id || offer_id->empty())
return false;
result.offer_id = *offer_id;
const std::string* name = value.FindStringKey("name");
if (!name || name->empty())
return false;
result.name = base::UTF8ToUTF16(*name);
const std::string* description = value.FindStringKey("description");
result.description =
description ? base::UTF8ToUTF16(*description) : base::string16();
const std::string* expiry = value.FindStringKey("expiry");
int64_t expiry_value;
if (!expiry || !base::StringToInt64(*expiry, &expiry_value))
return false;
result.expiry = expiry_value;
const std::string* merchant_domain = value.FindStringKey("merchant_domain");
if (!merchant_domain || !GURL(*merchant_domain).is_valid())
return false;
result.merchant_domain = GURL(*merchant_domain);
const auto* eligible_instrument_id =
value.FindKeyOfType("eligible_instrument_id", base::Value::Type::LIST);
if (eligible_instrument_id) {
for (const base::Value& id : eligible_instrument_id->GetList()) {
if (!id.GetString().empty()) {
result.eligible_instrument_id.push_back(id.GetString());
}
}
}
const auto* eligible_legacy_instrument_id = value.FindKeyOfType(
"eligible_legacy_instrument_id", base::Value::Type::LIST);
if (eligible_legacy_instrument_id) {
for (const base::Value& id : eligible_legacy_instrument_id->GetList()) {
if (!id.GetString().empty()) {
result.eligible_legacy_instrument_id.push_back(id.GetString());
}
}
}
return result.eligible_instrument_id.size() +
result.eligible_legacy_instrument_id.size() >
0;
}
const std::string app_locale_;
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)>
callback_;
base::Optional<std::vector<AutofillOfferData>> offers_;
};
} // namespace
const char PaymentsClient::kRecipientName[] = "recipient_name";
......@@ -1200,6 +1308,15 @@ void PaymentsClient::MigrateCards(
/*authenticate=*/true);
}
void PaymentsClient::GetOfferData(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback) {
IssueRequest(
std::make_unique<GetOfferDataRequest>(app_locale, std::move(callback)),
/*authenticate=*/true);
}
void PaymentsClient::CancelRequest() {
request_.reset();
resource_request_.reset();
......
......@@ -14,6 +14,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/card_unmask_delegate.h"
......@@ -316,6 +317,12 @@ class PaymentsClient {
const std::vector<MigratableCreditCard>& migratable_credit_cards,
MigrateCardsCallback callback);
// The user has opened a new tab and their offer data needs to be refreshed.
virtual void GetOfferData(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback);
// Cancels and clears the current |request_|.
void CancelRequest();
......
......@@ -91,6 +91,15 @@ void TestPaymentsClient::MigrateCards(
"this is display text");
}
void TestPaymentsClient::GetOfferData(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback) {
get_offer_data_calls_++;
if (should_return_offer_data_)
std::move(callback).Run(AutofillClient::SUCCESS, offers_);
}
void TestPaymentsClient::ShouldReturnUnmaskDetailsImmediately(
bool should_return_unmask_details) {
should_return_unmask_details_ = should_return_unmask_details;
......@@ -190,5 +199,10 @@ std::unique_ptr<base::Value> TestPaymentsClient::LegalMessage() {
}
}
void TestPaymentsClient::SetShouldReturnOfferData(
bool should_return_offer_data) {
should_return_offer_data_ = should_return_offer_data;
}
} // namespace payments
} // namespace autofill
......@@ -63,6 +63,12 @@ class TestPaymentsClient : public payments::PaymentsClient {
const std::vector<MigratableCreditCard>& migratable_credit_cards,
MigrateCardsCallback callback) override;
void GetOfferData(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback)
override;
// Some metrics are affected by the latency of GetUnmaskDetails, so it is
// useful to control whether or not GetUnmaskDetails() is responded to.
void ShouldReturnUnmaskDetailsImmediately(bool should_return_unmask_details);
......@@ -84,6 +90,8 @@ class TestPaymentsClient : public payments::PaymentsClient {
void SetUseInvalidLegalMessageInGetUploadDetails(
bool use_invalid_legal_message);
void SetShouldReturnOfferData(bool should_return_offer_data);
payments::PaymentsClient::UnmaskDetails* unmask_details() {
return &unmask_details_;
}
......@@ -106,6 +114,7 @@ class TestPaymentsClient : public payments::PaymentsClient {
PaymentsClient::UploadCardSource upload_card_source_in_request() const {
return upload_card_source_;
}
int get_offer_data_calls() const { return get_offer_data_calls_; }
private:
std::string server_id_;
......@@ -126,6 +135,9 @@ class TestPaymentsClient : public payments::PaymentsClient {
std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_;
bool use_invalid_legal_message_ = false;
std::unique_ptr<base::Value> LegalMessage();
std::vector<AutofillOfferData> offers_;
int get_offer_data_calls_ = 0;
bool should_return_offer_data_ = true;
DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment