blob: ed8a677c773a064dc65af0ef980625097e88f69f [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/commerce/core/commerce_heuristics_data.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/no_destructor.h"
#include "base/time/time_delta_from_string.h"
namespace commerce_heuristics {
namespace {
// CommerceHintHeuristics types.
constexpr char kMerchantNameType[] = "merchant_name";
constexpr char kMerchantCartURLType[] = "cart_url";
constexpr char kMerchantCartURLRegexType[] = "cart_url_regex";
constexpr char kMerchantCheckoutURLRegexType[] = "checkout_url_regex";
constexpr char kMerchantPurchaseURLRegexType[] = "purchase_url_regex";
constexpr char kSkipAddToCartRegexType[] = "skip_add_to_cart_regex";
// CommerceGlobalHeuristics types.
constexpr char kSkipProductPatternType[] = "sensitive_product_regex";
constexpr char kRuleDiscountPartnerMerchantPatternType[] =
"rule_discount_partner_merchant_regex";
constexpr char kCouponDiscountPartnerMerchantPatternType[] =
"coupon_discount_partner_merchant_regex";
constexpr char kNoDiscountMerchantPatternType[] = "no_discount_merchant_regex";
constexpr char kCartPagetURLPatternType[] = "cart_page_url_regex";
constexpr char kCheckoutPageURLPatternType[] = "checkout_page_url_regex";
constexpr char kPurchaseButtonTextPatternType[] = "purchase_button_text_regex";
constexpr char kAddToCartRequestPatternType[] = "add_to_cart_request_regex";
constexpr char kDiscountFetchDelayType[] = "discount_fetch_delay";
} // namespace
// static
CommerceHeuristicsData& CommerceHeuristicsData::GetInstance() {
static base::NoDestructor<CommerceHeuristicsData> instance;
return *instance;
}
CommerceHeuristicsData::CommerceHeuristicsData() = default;
CommerceHeuristicsData::~CommerceHeuristicsData() = default;
void CommerceHeuristicsData::UpdateVersion(base::Version version) {
version_ = std::move(version);
}
const std::string CommerceHeuristicsData::GetVersion() {
if (!version_.IsValid())
return std::string();
return version_.GetString();
}
bool CommerceHeuristicsData::PopulateDataFromComponent(
const std::string& hint_json_data,
const std::string& global_json_data,
const std::string& product_id_json_data,
const std::string& cart_extraction_script) {
auto hint_json_value = base::JSONReader::ReadDict(hint_json_data);
auto global_json_value = base::JSONReader::ReadDict(global_json_data);
if (!hint_json_value) {
return false;
}
if (!global_json_value) {
return false;
}
hint_heuristics_ = std::move(*hint_json_value);
global_heuristics_string_ = global_json_data;
global_heuristics_ = std::move(*global_json_value);
// Global regex patterns.
product_skip_pattern_ = ConstructGlobalRegex(kSkipProductPatternType);
rule_discount_partner_merchant_pattern_ =
ConstructGlobalRegex(kRuleDiscountPartnerMerchantPatternType);
coupon_discount_partner_merchant_pattern_ =
ConstructGlobalRegex(kCouponDiscountPartnerMerchantPatternType);
no_discount_merchant_pattern_ =
ConstructGlobalRegex(kNoDiscountMerchantPatternType);
cart_url_pattern_ = ConstructGlobalRegex(kCartPagetURLPatternType);
checkout_url_pattern_ = ConstructGlobalRegex(kCheckoutPageURLPatternType);
purchase_button_pattern_ =
ConstructGlobalRegex(kPurchaseButtonTextPatternType);
add_to_cart_request_pattern_ =
ConstructGlobalRegex(kAddToCartRequestPatternType);
product_id_json_ = product_id_json_data;
cart_extraction_script_ = cart_extraction_script;
domain_cart_url_pattern_mapping_.clear();
domain_checkout_url_pattern_mapping_.clear();
domain_purchase_url_pattern_mapping_.clear();
domain_skip_add_to_cart_pattern_mapping_.clear();
return true;
}
std::optional<std::string> CommerceHeuristicsData::GetMerchantName(
const std::string& domain) {
return GetCommerceHintHeuristics(kMerchantNameType, domain);
}
std::optional<std::string> CommerceHeuristicsData::GetMerchantCartURL(
const std::string& domain) {
return GetCommerceHintHeuristics(kMerchantCartURLType, domain);
}
std::optional<std::string>
CommerceHeuristicsData::GetHintHeuristicsJSONForDomain(
const std::string& domain) {
if (!hint_heuristics_.contains(domain)) {
return std::nullopt;
}
base::Value::Dict domain_heuristics =
hint_heuristics_.FindDict(domain)->Clone();
if (domain_heuristics.empty()) {
return std::nullopt;
}
base::Value::Dict res_dic;
res_dic.Set(domain, std::move(domain_heuristics));
std::string res_string;
base::JSONWriter::Write(res_dic, &res_string);
return std::optional<std::string>(res_string);
}
std::optional<std::string> CommerceHeuristicsData::GetGlobalHeuristicsJSON() {
return global_heuristics_string_;
}
const re2::RE2* CommerceHeuristicsData::GetProductSkipPattern() {
return product_skip_pattern_.get();
}
const re2::RE2*
CommerceHeuristicsData::GetRuleDiscountPartnerMerchantPattern() {
return rule_discount_partner_merchant_pattern_.get();
}
const re2::RE2*
CommerceHeuristicsData::GetCouponDiscountPartnerMerchantPattern() {
return coupon_discount_partner_merchant_pattern_.get();
}
const re2::RE2* CommerceHeuristicsData::GetNoDiscountMerchantPattern() {
return no_discount_merchant_pattern_.get();
}
const re2::RE2* CommerceHeuristicsData::GetCartPageURLPattern() {
return cart_url_pattern_.get();
}
const re2::RE2* CommerceHeuristicsData::GetCheckoutPageURLPattern() {
return checkout_url_pattern_.get();
}
const re2::RE2* CommerceHeuristicsData::GetPurchaseButtonTextPattern() {
return purchase_button_pattern_.get();
}
const re2::RE2* CommerceHeuristicsData::GetAddToCartRequestPattern() {
return add_to_cart_request_pattern_.get();
}
const re2::RE2* CommerceHeuristicsData::GetCartPageURLPatternForDomain(
const std::string& domain) {
return GetCommerceHintHeuristicsRegex(domain_cart_url_pattern_mapping_,
kMerchantCartURLRegexType, domain);
}
const re2::RE2* CommerceHeuristicsData::GetCheckoutPageURLPatternForDomain(
const std::string& domain) {
return GetCommerceHintHeuristicsRegex(domain_checkout_url_pattern_mapping_,
kMerchantCheckoutURLRegexType, domain);
}
const re2::RE2* CommerceHeuristicsData::GetPurchasePageURLPatternForDomain(
const std::string& domain) {
return GetCommerceHintHeuristicsRegex(domain_purchase_url_pattern_mapping_,
kMerchantPurchaseURLRegexType, domain);
}
const re2::RE2* CommerceHeuristicsData::GetSkipAddToCartPatternForDomain(
const std::string& domain) {
return GetCommerceHintHeuristicsRegex(
domain_skip_add_to_cart_pattern_mapping_, kSkipAddToCartRegexType,
domain);
}
std::string CommerceHeuristicsData::GetProductIDExtractionJSON() {
return product_id_json_;
}
std::string CommerceHeuristicsData::GetCartProductExtractionScript() {
return cart_extraction_script_;
}
std::optional<base::TimeDelta> CommerceHeuristicsData::GetDiscountFetchDelay() {
auto delay_value_optional =
GetCommerceGlobalHeuristics(kDiscountFetchDelayType);
if (!delay_value_optional.has_value()) {
return std::nullopt;
}
return base::TimeDeltaFromString(*delay_value_optional);
}
std::optional<std::string> CommerceHeuristicsData::GetCommerceHintHeuristics(
const std::string& type,
const std::string& domain) {
if (!hint_heuristics_.contains(domain)) {
return std::nullopt;
}
const base::Value::Dict* domain_heuristics =
hint_heuristics_.FindDict(domain);
if (!domain_heuristics || domain_heuristics->empty() ||
!domain_heuristics->contains(type)) {
return std::nullopt;
}
return std::optional<std::string>(*domain_heuristics->FindString(type));
}
std::optional<std::string> CommerceHeuristicsData::GetCommerceGlobalHeuristics(
const std::string& type) {
if (!global_heuristics_.contains(type)) {
return std::nullopt;
}
return std::optional<std::string>(*global_heuristics_.FindString(type));
}
const re2::RE2* CommerceHeuristicsData::GetCommerceHintHeuristicsRegex(
std::map<std::string, std::unique_ptr<re2::RE2>>& map,
const std::string type,
const std::string domain) {
if (map.find(domain) != map.end())
return map.at(domain).get();
std::optional<std::string> pattern = GetCommerceHintHeuristics(type, domain);
if (!pattern.has_value())
return nullptr;
re2::RE2::Options options;
options.set_case_sensitive(false);
map.emplace(domain, std::make_unique<re2::RE2>(*pattern, options));
return map.at(domain).get();
}
std::unique_ptr<re2::RE2> CommerceHeuristicsData::ConstructGlobalRegex(
const std::string& type) {
if (!GetCommerceGlobalHeuristics(type).has_value()) {
return nullptr;
}
std::string pattern = *GetCommerceGlobalHeuristics(type);
re2::RE2::Options options;
options.set_case_sensitive(false);
return std::make_unique<re2::RE2>(std::move(pattern), options);
}
} // namespace commerce_heuristics