diff --git a/browser/ntp_background/view_counter_service_factory.cc b/browser/ntp_background/view_counter_service_factory.cc index e009dff70614..d6cff1cbfefa 100644 --- a/browser/ntp_background/view_counter_service_factory.cc +++ b/browser/ntp_background/view_counter_service_factory.cc @@ -18,6 +18,7 @@ #include "brave/components/ntp_background_images/browser/ntp_background_images_service.h" #include "brave/components/ntp_background_images/browser/ntp_background_images_source.h" #include "brave/components/ntp_background_images/browser/ntp_sponsored_images_source.h" +#include "brave/components/ntp_background_images/browser/ntp_sponsored_rich_media_source.h" #include "brave/components/ntp_background_images/browser/view_counter_service.h" #include "brave/components/ntp_background_images/buildflags/buildflags.h" #include "chrome/browser/browser_process.h" @@ -71,7 +72,8 @@ ViewCounterServiceFactory::BuildServiceInstanceForBrowserContext( g_brave_browser_process->ntp_background_images_service()) { Profile* profile = Profile::FromBrowserContext(browser_context); bool is_supported_locale = false; - auto* ads_service = brave_ads::AdsServiceFactory::GetForProfile(profile); + brave_ads::AdsService* ads_service = + brave_ads::AdsServiceFactory::GetForProfile(profile); if (ads_service) { is_supported_locale = brave_ads::IsSupportedRegion(); } @@ -79,6 +81,9 @@ ViewCounterServiceFactory::BuildServiceInstanceForBrowserContext( browser_context, std::make_unique(service)); content::URLDataSource::Add( browser_context, std::make_unique(service)); + content::URLDataSource::Add( + browser_context, + std::make_unique(service)); std::unique_ptr ntp_p3a_helper; if (g_brave_browser_process->p3a_service() != nullptr) { diff --git a/browser/ui/webui/new_tab_page/brave_new_tab_message_handler.cc b/browser/ui/webui/new_tab_page/brave_new_tab_message_handler.cc index ff71f0f455ea..3afed5cae133 100644 --- a/browser/ui/webui/new_tab_page/brave_new_tab_message_handler.cc +++ b/browser/ui/webui/new_tab_page/brave_new_tab_message_handler.cc @@ -209,6 +209,11 @@ void BraveNewTabMessageHandler::RegisterMessages() { base::BindRepeating( &BraveNewTabMessageHandler::HandleBrandedWallpaperLogoClicked, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "triggerSponsoredRichMediaAdEvent", + base::BindRepeating( + &BraveNewTabMessageHandler::HandleTriggerSponsoredRichMediaAdEvent, + base::Unretained(this))); web_ui()->RegisterMessageCallback( "getWallpaperData", base::BindRepeating(&BraveNewTabMessageHandler::HandleGetWallpaperData, @@ -475,6 +480,34 @@ void BraveNewTabMessageHandler::HandleBrandedWallpaperLogoClicked( } } +void BraveNewTabMessageHandler::HandleTriggerSponsoredRichMediaAdEvent( + const base::Value::List& args) { + AllowJavascript(); + if (args.size() != 2) { + LOG(ERROR) << "Invalid input"; + return; + } + + const base::Value::Dict* wallpaper = args[0].GetIfDict(); + if (!wallpaper) { + return; + } + const std::string* placement_id = + wallpaper->FindStringByDottedPath(ntp_background_images::kWallpaperIDKey); + const std::string* creative_instance_id = + wallpaper->FindString(ntp_background_images::kCreativeInstanceIDKey); + const std::string* ad_event_type = args[1].GetIfString(); + if (!placement_id || !creative_instance_id || !ad_event_type) { + return; + } + + if (ntp_background_images::ViewCounterService* service = + ViewCounterServiceFactory::GetForProfile(profile_)) { + service->TriggerSponsoredRichMediaAdEvent( + *placement_id, *creative_instance_id, *ad_event_type); + } +} + void BraveNewTabMessageHandler::HandleGetWallpaperData( const base::Value::List& args) { AllowJavascript(); diff --git a/browser/ui/webui/new_tab_page/brave_new_tab_message_handler.h b/browser/ui/webui/new_tab_page/brave_new_tab_message_handler.h index 402e5d21a287..5aab65102fc5 100644 --- a/browser/ui/webui/new_tab_page/brave_new_tab_message_handler.h +++ b/browser/ui/webui/new_tab_page/brave_new_tab_message_handler.h @@ -59,6 +59,7 @@ class BraveNewTabMessageHandler : public content::WebUIMessageHandler, void HandleSaveNewTabPagePref(const base::Value::List& args); void HandleRegisterNewTabPageView(const base::Value::List& args); void HandleBrandedWallpaperLogoClicked(const base::Value::List& args); + void HandleTriggerSponsoredRichMediaAdEvent(const base::Value::List& args); void HandleGetWallpaperData(const base::Value::List& args); void HandleCustomizeClicked(const base::Value::List& args); diff --git a/browser/ui/webui/new_tab_page/brave_new_tab_ui.cc b/browser/ui/webui/new_tab_page/brave_new_tab_ui.cc index 1548d5d9cb46..32763c377907 100644 --- a/browser/ui/webui/new_tab_page/brave_new_tab_ui.cc +++ b/browser/ui/webui/new_tab_page/brave_new_tab_ui.cc @@ -23,6 +23,7 @@ #include "brave/components/brave_new_tab/resources/grit/brave_new_tab_generated_map.h" #include "brave/components/brave_news/browser/brave_news_controller.h" #include "brave/components/brave_news/common/features.h" +#include "brave/components/constants/webui_url_constants.h" #include "brave/components/l10n/common/localization_util.h" #include "brave/components/misc_metrics/new_tab_metrics.h" #include "brave/components/ntp_background_images/browser/ntp_custom_images_source.h" @@ -36,6 +37,7 @@ #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" +#include "content/public/common/url_constants.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "ui/webui/resources/cr_components/searchbox/searchbox.mojom.h" @@ -76,6 +78,8 @@ BraveNewTabUI::BraveNewTabUI(content::WebUI* web_ui, const std::string& name) content::WebUIDataSource* source = CreateAndAddWebUIDataSource( web_ui, name, kBraveNewTabGenerated, IDR_BRAVE_NEW_TAB_HTML); + web_ui->AddRequestableScheme(content::kChromeUIUntrustedScheme); + AddBackgroundColorToSource(source, web_contents); // Lottie animations tick on a worker thread and requires the document CSP to @@ -127,6 +131,10 @@ BraveNewTabUI::BraveNewTabUI(content::WebUI* web_ui, const std::string& name) std::make_unique( ntp_custom_background_images_service)); } + + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::FrameSrc, + std::string("frame-src ") + kNTPSponsoredRichMediaUrl + ";"); } BraveNewTabUI::~BraveNewTabUI() = default; diff --git a/components/brave_ads/browser/ads_service_impl.cc b/components/brave_ads/browser/ads_service_impl.cc index 5f446b51228f..8eb544ee1171 100644 --- a/components/brave_ads/browser/ads_service_impl.cc +++ b/components/brave_ads/browser/ads_service_impl.cc @@ -1283,6 +1283,17 @@ void AdsServiceImpl::OnFailedToPrefetchNewTabPageAd( /*intentional*/ base::DoNothing()); } +void AdsServiceImpl::ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) { + if (!bat_ads_associated_remote_.is_bound()) { + return std::move(callback).Run(/*success*/ false); + } + + bat_ads_associated_remote_->ParseAndSaveCreativeNewTabPageAds( + json, std::move(callback)); +} + void AdsServiceImpl::TriggerNewTabPageAdEvent( const std::string& placement_id, const std::string& creative_instance_id, diff --git a/components/brave_ads/browser/ads_service_impl.h b/components/brave_ads/browser/ads_service_impl.h index 3e2c6e7ef173..2a69abb3c43f 100644 --- a/components/brave_ads/browser/ads_service_impl.h +++ b/components/brave_ads/browser/ads_service_impl.h @@ -249,6 +249,9 @@ class AdsServiceImpl final : public AdsService, void OnFailedToPrefetchNewTabPageAd( const std::string& placement_id, const std::string& creative_instance_id) override; + void ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) override; void TriggerNewTabPageAdEvent( const std::string& placement_id, const std::string& creative_instance_id, diff --git a/components/brave_ads/browser/ads_service_mock.h b/components/brave_ads/browser/ads_service_mock.h index 705731d5389d..7e30585a46d5 100644 --- a/components/brave_ads/browser/ads_service_mock.h +++ b/components/brave_ads/browser/ads_service_mock.h @@ -69,6 +69,9 @@ class AdsServiceMock : public AdsService { MOCK_METHOD(void, OnFailedToPrefetchNewTabPageAd, (const std::string&, const std::string&)); + MOCK_METHOD(void, + ParseAndSaveCreativeNewTabPageAds, + (const std::string&, ParseAndSaveCreativeNewTabPageAdsCallback)); MOCK_METHOD(void, TriggerPromotedContentAdEvent, diff --git a/components/brave_ads/core/browser/service/ads_service.h b/components/brave_ads/core/browser/service/ads_service.h index 41df01e2a65a..8d1e3048081f 100644 --- a/components/brave_ads/core/browser/service/ads_service.h +++ b/components/brave_ads/core/browser/service/ads_service.h @@ -139,6 +139,12 @@ class AdsService : public KeyedService { const std::string& placement_id, const std::string& creative_instance_id) = 0; + // Called to parse and save creative new tab page ads. The callback takes one + // argument - `bool` is set to `true` if successful otherwise `false`. + virtual void ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) = 0; + // Called when a user views or interacts with a new tab page ad to trigger a // `mojom_ad_event_type` event for the specified `placement_id` and // `creative_instance_id`. `placement_id` should be a 128-bit random GUID in diff --git a/components/brave_ads/core/internal/BUILD.gn b/components/brave_ads/core/internal/BUILD.gn index 065164a88f7c..a4c02db771f1 100644 --- a/components/brave_ads/core/internal/BUILD.gn +++ b/components/brave_ads/core/internal/BUILD.gn @@ -267,6 +267,7 @@ static_library("internal") { "ad_units/inline_content_ad/inline_content_ad_handler.h", "ad_units/inline_content_ad/inline_content_ad_info.cc", "ad_units/inline_content_ad/inline_content_ad_value_util.cc", + "ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.cc", "ad_units/new_tab_page_ad/new_tab_page_ad_feature.cc", "ad_units/new_tab_page_ad/new_tab_page_ad_feature.h", "ad_units/new_tab_page_ad/new_tab_page_ad_handler.cc", @@ -335,12 +336,6 @@ static_library("internal") { "catalog/campaign/creative_set/creative/inline_content_ad/catalog_creative_inline_content_ad_info.h", "catalog/campaign/creative_set/creative/inline_content_ad/catalog_inline_content_ad_payload_info.cc", "catalog/campaign/creative_set/creative/inline_content_ad/catalog_inline_content_ad_payload_info.h", - "catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_creative_new_tab_page_ad_info.h", - "catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.cc", - "catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.h", - "catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_focal_point_info.h", - "catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.cc", - "catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.h", "catalog/campaign/creative_set/creative/notification_ad/catalog_creative_notification_ad_info.h", "catalog/campaign/creative_set/creative/notification_ad/catalog_notification_ad_payload_info.h", "catalog/campaign/creative_set/creative/promoted_content_ad/catalog_creative_promoted_content_ad_info.h", @@ -524,8 +519,8 @@ static_library("internal") { "creatives/creative_ad_util.h", "creatives/creative_ads_database_table.cc", "creatives/creative_ads_database_table.h", - "creatives/creative_ads_database_util.cc", - "creatives/creative_ads_database_util.h", + "creatives/creative_ads_database_table_util.cc", + "creatives/creative_ads_database_table_util.h", "creatives/creative_daypart_info.h", "creatives/creatives_builder.cc", "creatives/creatives_builder.h", @@ -533,12 +528,8 @@ static_library("internal") { "creatives/creatives_info.h", "creatives/dayparts_database_table.cc", "creatives/dayparts_database_table.h", - "creatives/dayparts_database_util.cc", - "creatives/dayparts_database_util.h", "creatives/geo_targets_database_table.cc", "creatives/geo_targets_database_table.h", - "creatives/geo_targets_database_util.cc", - "creatives/geo_targets_database_util.h", "creatives/inline_content_ads/creative_inline_content_ad_info.cc", "creatives/inline_content_ads/creative_inline_content_ad_info.h", "creatives/inline_content_ads/creative_inline_content_ads_database_table.cc", @@ -549,11 +540,6 @@ static_library("internal") { "creatives/inline_content_ads/inline_content_ad_builder.h", "creatives/new_tab_page_ads/creative_new_tab_page_ad_info.cc", "creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h", - "creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_focal_point_info.h", - "creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.cc", - "creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.h", - "creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.cc", - "creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h", "creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.cc", "creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.h", "creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.cc", @@ -580,8 +566,6 @@ static_library("internal") { "creatives/promoted_content_ads/promoted_content_ad_builder.h", "creatives/segments_database_table.cc", "creatives/segments_database_table.h", - "creatives/segments_database_util.cc", - "creatives/segments_database_util.h", "database/database.cc", "database/database.h", "database/database_maintenance.cc", diff --git a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.cc b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.cc new file mode 100644 index 000000000000..1f012497bdc4 --- /dev/null +++ b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.cc @@ -0,0 +1,37 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.h" + +#include "base/containers/fixed_flat_map.h" +#include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" + +namespace brave_ads { + +namespace { + +constexpr auto kNewTabPageAdEventTypeMap = + base::MakeFixedFlatMap({ + {"served", mojom::NewTabPageAdEventType::kServedImpression}, + {"view", mojom::NewTabPageAdEventType::kViewedImpression}, + {"click", mojom::NewTabPageAdEventType::kClicked}, + {"media_play", mojom::NewTabPageAdEventType::kMediaPlay}, + {"media_25", mojom::NewTabPageAdEventType::kMedia25}, + {"media_100", brave_ads::mojom::NewTabPageAdEventType::kMedia100}, + }); + +} // namespace + +std::optional +ToMojomNewTabPageAdEventType(const std::string& event_type) { + const auto iter = kNewTabPageAdEventTypeMap.find(event_type); + if (iter == kNewTabPageAdEventTypeMap.cend()) { + return std::nullopt; + } + + return iter->second; +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util_unittest.cc b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util_unittest.cc new file mode 100644 index 000000000000..5f83a4a1e961 --- /dev/null +++ b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util_unittest.cc @@ -0,0 +1,40 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.h" + +#include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=BraveAds* + +namespace brave_ads { + +TEST(BraveAdsNewTabPageAdEventTypeUtilTest, ToMojomNewTabPageAdEventType) { + // Act & Assert + EXPECT_EQ(ToMojomNewTabPageAdEventType("served"), + mojom::NewTabPageAdEventType::kServedImpression); + + EXPECT_EQ(ToMojomNewTabPageAdEventType("view"), + mojom::NewTabPageAdEventType::kViewedImpression); + + EXPECT_EQ(ToMojomNewTabPageAdEventType("click"), + mojom::NewTabPageAdEventType::kClicked); + + EXPECT_EQ(ToMojomNewTabPageAdEventType("media_play"), + mojom::NewTabPageAdEventType::kMediaPlay); + + EXPECT_EQ(ToMojomNewTabPageAdEventType("media_25"), + mojom::NewTabPageAdEventType::kMedia25); + + EXPECT_EQ(ToMojomNewTabPageAdEventType("media_100"), + mojom::NewTabPageAdEventType::kMedia100); + + EXPECT_EQ(ToMojomNewTabPageAdEventType(""), std::nullopt); + + EXPECT_EQ(ToMojomNewTabPageAdEventType("foobar"), std::nullopt); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_handler.cc b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_handler.cc index 658ddc66911b..4e84a42761d6 100644 --- a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_handler.cc +++ b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_handler.cc @@ -160,14 +160,8 @@ void NewTabPageAdHandler::OnDidServeNewTabPageAd(const NewTabPageAdInfo& ad) { << " advertiserId: " << ad.advertiser_id << "\n" << " segment: " << ad.segment << "\n" << " companyName: " << ad.company_name << "\n" - << " imageUrl: " << ad.image_url << "\n" << " alt: " << ad.alt << "\n" - << " targetUrl: " << ad.target_url << "\n" - << " wallpaper:\n" - << " imageUrl: " << ad.wallpapers[0].image_url << "\n" - << " focalPoint:\n" - << " x: " << ad.wallpapers[0].focal_point.x << "\n" - << " y: " << ad.wallpapers[0].focal_point.y); + << " targetUrl: " << ad.target_url); } void NewTabPageAdHandler::OnDidFireNewTabPageAdServedEvent( diff --git a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_info.cc b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_info.cc index 9d79c34b7ab0..f579f958d2f9 100644 --- a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_info.cc +++ b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_info.cc @@ -22,8 +22,7 @@ NewTabPageAdInfo& NewTabPageAdInfo::operator=( NewTabPageAdInfo::~NewTabPageAdInfo() = default; bool NewTabPageAdInfo::IsValid() const { - return AdInfo::IsValid() && !company_name.empty() && image_url.is_valid() && - !alt.empty() && !wallpapers.empty(); + return AdInfo::IsValid() && !company_name.empty() && !alt.empty(); } } // namespace brave_ads diff --git a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_value_util.cc b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_value_util.cc index e6066ce9aaeb..5f60754ae0d7 100644 --- a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_value_util.cc +++ b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_value_util.cc @@ -5,10 +5,6 @@ #include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_value_util.h" -#include -#include -#include - #include "brave/components/brave_ads/core/public/ad_units/ad_type.h" #include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_constants.h" #include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_info.h" @@ -16,18 +12,6 @@ namespace brave_ads { base::Value::Dict NewTabPageAdToValue(const NewTabPageAdInfo& ad) { - base::Value::List wallpapers; - for (const NewTabPageAdWallpaperInfo& wallpaper : ad.wallpapers) { - wallpapers.Append( - base::Value::Dict() - .Set(kNewTabPageAdImageUrlKey, wallpaper.image_url.spec()) - .Set(kNewTabPageAdFocalPointKey, - base::Value::Dict() - .Set(kNewTabPageAdFocalPointXKey, wallpaper.focal_point.x) - .Set(kNewTabPageAdFocalPointYKey, - wallpaper.focal_point.y))); - } - return base::Value::Dict() .Set(kNewTabPageAdTypeKey, ToString(ad.type)) .Set(kNewTabPageAdPlacementIdKey, ad.placement_id) @@ -37,10 +21,8 @@ base::Value::Dict NewTabPageAdToValue(const NewTabPageAdInfo& ad) { .Set(kNewTabPageAdAdvertiserIdKey, ad.advertiser_id) .Set(kNewTabPageAdSegmentKey, ad.segment) .Set(kNewTabPageAdCompanyNameKey, ad.company_name) - .Set(kNewTabPageAdImageUrlKey, ad.image_url.spec()) .Set(kNewTabPageAdAltKey, ad.alt) - .Set(kNewTabPageAdTargetUrlKey, ad.target_url.spec()) - .Set(kNewTabPageAdWallpapersKey, std::move(wallpapers)); + .Set(kNewTabPageAdTargetUrlKey, ad.target_url.spec()); } NewTabPageAdInfo NewTabPageAdFromValue(const base::Value::Dict& dict) { @@ -80,52 +62,10 @@ NewTabPageAdInfo NewTabPageAdFromValue(const base::Value::Dict& dict) { ad.company_name = *value; } - if (const auto* const value = dict.FindString(kNewTabPageAdImageUrlKey)) { - ad.image_url = GURL(*value); - } - if (const auto* const value = dict.FindString(kNewTabPageAdAltKey)) { ad.alt = *value; } - if (const auto* const wallpapers_list = - dict.FindList(kNewTabPageAdWallpapersKey)) { - for (const auto& item : *wallpapers_list) { - const auto* const item_dict = item.GetIfDict(); - if (!item_dict) { - continue; - } - - const std::string* const image_url = - item_dict->FindString(kNewTabPageAdImageUrlKey); - if (!image_url) { - continue; - } - - const auto* const focal_point_dict = - item_dict->FindDict(kNewTabPageAdFocalPointKey); - if (!focal_point_dict) { - continue; - } - - const std::optional focal_point_x = - focal_point_dict->FindInt(kNewTabPageAdFocalPointXKey); - if (!focal_point_x) { - continue; - } - - const std::optional focal_point_y = - focal_point_dict->FindInt(kNewTabPageAdFocalPointYKey); - if (!focal_point_y) { - continue; - } - - ad.wallpapers.emplace_back( - GURL(*image_url), - NewTabPageAdWallpaperFocalPointInfo{*focal_point_x, *focal_point_y}); - } - } - if (const auto* const value = dict.FindString(kNewTabPageAdTargetUrlKey)) { ad.target_url = GURL(*value); } diff --git a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_value_util_unittest.cc b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_value_util_unittest.cc index 51190108b03f..e0262628958d 100644 --- a/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_value_util_unittest.cc +++ b/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_value_util_unittest.cc @@ -28,20 +28,10 @@ constexpr char kNewTabPageAdAsJson[] = "company_name": "Test Ad Company Name", "creative_instance_id": "546fe7b0-5047-4f28-a11c-81f14edcf0f6", "creative_set_id": "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123", - "image_url": "https://brave.com/image", "placement_id": "9bac9ae4-693c-4569-9b3e-300e357780cf", "segment": "untargeted", "target_url": "https://brave.com/", - "type": "new_tab_page_ad", - "wallpapers": [ - { - "focal_point": { - "x": 1280, - "y": 720 - }, - "image_url": "https://brave.com/wallpaper_image" - } - ] + "type": "new_tab_page_ad" })"; } // namespace diff --git a/components/brave_ads/core/internal/ads_impl.cc b/components/brave_ads/core/internal/ads_impl.cc index f1847c87a325..75cf8c4acfb6 100644 --- a/components/brave_ads/core/internal/ads_impl.cc +++ b/components/brave_ads/core/internal/ads_impl.cc @@ -16,6 +16,7 @@ #include "brave/components/brave_ads/core/internal/ads_core/ads_core_util.h" #include "brave/components/brave_ads/core/internal/ads_notifier_manager.h" #include "brave/components/brave_ads/core/internal/common/logging_util.h" +#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.h" #include "brave/components/brave_ads/core/internal/creatives/notification_ads/notification_ad_manager.h" #include "brave/components/brave_ads/core/internal/database/database_maintenance.h" #include "brave/components/brave_ads/core/internal/database/database_manager.h" @@ -176,6 +177,20 @@ void AdsImpl::TriggerInlineContentAdEvent( std::move(callback)); } +void AdsImpl::ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) { + if (task_queue_.should_queue()) { + return task_queue_.Add( + base::BindOnce(&AdsImpl::ParseAndSaveCreativeNewTabPageAds, + weak_factory_.GetWeakPtr(), json, std::move(callback))); + } + + const bool success = database::ParseAndSaveCreativeNewTabPageAds(json); + + std::move(callback).Run(success); +} + void AdsImpl::MaybeServeNewTabPageAd(MaybeServeNewTabPageAdCallback callback) { if (task_queue_.should_queue()) { return task_queue_.Add(base::BindOnce(&AdsImpl::MaybeServeNewTabPageAd, diff --git a/components/brave_ads/core/internal/ads_impl.h b/components/brave_ads/core/internal/ads_impl.h index 192125266ecc..71526e699d9d 100644 --- a/components/brave_ads/core/internal/ads_impl.h +++ b/components/brave_ads/core/internal/ads_impl.h @@ -68,6 +68,9 @@ class AdsImpl final : public Ads { mojom::InlineContentAdEventType mojom_ad_event_type, TriggerAdEventCallback callback) override; + void ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) override; void MaybeServeNewTabPageAd(MaybeServeNewTabPageAdCallback callback) override; void TriggerNewTabPageAdEvent( const std::string& placement_id, diff --git a/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_creative_set_info.cc b/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_creative_set_info.cc index ae1914b18410..8d2babf691cb 100644 --- a/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_creative_set_info.cc +++ b/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_creative_set_info.cc @@ -41,7 +41,6 @@ bool CatalogCreativeSetInfo::operator==( conversions == other.conversions && creative_notification_ads == other.creative_notification_ads && creative_inline_content_ads == other.creative_inline_content_ads && - creative_new_tab_page_ads == other.creative_new_tab_page_ads && creative_promoted_content_ads == other.creative_promoted_content_ads; } diff --git a/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_creative_set_info.h b/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_creative_set_info.h index 29cd10ce54bc..ab5c0b0f3c00 100644 --- a/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_creative_set_info.h +++ b/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_creative_set_info.h @@ -13,7 +13,6 @@ #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_os_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_segment_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/inline_content_ad/catalog_creative_inline_content_ad_info.h" -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_creative_new_tab_page_ad_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/notification_ad/catalog_creative_notification_ad_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/promoted_content_ad/catalog_creative_promoted_content_ad_info.h" @@ -47,7 +46,6 @@ struct CatalogCreativeSetInfo final { CatalogConversionList conversions; CatalogCreativeNotificationAdList creative_notification_ads; CatalogCreativeInlineContentAdList creative_inline_content_ads; - CatalogCreativeNewTabPageAdList creative_new_tab_page_ads; CatalogCreativePromotedContentAdList creative_promoted_content_ads; }; diff --git a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_creative_new_tab_page_ad_info.h b/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_creative_new_tab_page_ad_info.h deleted file mode 100644 index 85fe87a90c30..000000000000 --- a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_creative_new_tab_page_ad_info.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (c) 2020 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_CREATIVE_NEW_TAB_PAGE_AD_INFO_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_CREATIVE_NEW_TAB_PAGE_AD_INFO_H_ - -#include - -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/catalog_creative_info.h" -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.h" - -namespace brave_ads { - -struct CatalogCreativeNewTabPageAdInfo final : CatalogCreativeInfo { - bool operator==(const CatalogCreativeNewTabPageAdInfo&) const = default; - - CatalogNewTabPageAdPayloadInfo payload; -}; - -using CatalogCreativeNewTabPageAdList = - std::vector; - -} // namespace brave_ads - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_CREATIVE_NEW_TAB_PAGE_AD_INFO_H_ diff --git a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.cc b/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.cc deleted file mode 100644 index e64fe23b7ee0..000000000000 --- a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 2020 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.h" - -namespace brave_ads { - -CatalogNewTabPageAdPayloadInfo::CatalogNewTabPageAdPayloadInfo() = default; - -CatalogNewTabPageAdPayloadInfo::CatalogNewTabPageAdPayloadInfo( - const CatalogNewTabPageAdPayloadInfo& other) = default; - -CatalogNewTabPageAdPayloadInfo& CatalogNewTabPageAdPayloadInfo::operator=( - const CatalogNewTabPageAdPayloadInfo& other) = default; - -CatalogNewTabPageAdPayloadInfo::CatalogNewTabPageAdPayloadInfo( - CatalogNewTabPageAdPayloadInfo&& other) noexcept = default; - -CatalogNewTabPageAdPayloadInfo& CatalogNewTabPageAdPayloadInfo::operator=( - CatalogNewTabPageAdPayloadInfo&& other) noexcept = default; - -CatalogNewTabPageAdPayloadInfo::~CatalogNewTabPageAdPayloadInfo() = default; - -} // namespace brave_ads diff --git a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.h b/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.h deleted file mode 100644 index 913fe12ec612..000000000000 --- a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_payload_info.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (c) 2020 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_PAYLOAD_INFO_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_PAYLOAD_INFO_H_ - -#include - -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.h" -#include "url/gurl.h" - -namespace brave_ads { - -struct CatalogNewTabPageAdPayloadInfo final { - CatalogNewTabPageAdPayloadInfo(); - - CatalogNewTabPageAdPayloadInfo(const CatalogNewTabPageAdPayloadInfo&); - CatalogNewTabPageAdPayloadInfo& operator=( - const CatalogNewTabPageAdPayloadInfo&); - - CatalogNewTabPageAdPayloadInfo(CatalogNewTabPageAdPayloadInfo&&) noexcept; - CatalogNewTabPageAdPayloadInfo& operator=( - CatalogNewTabPageAdPayloadInfo&&) noexcept; - - ~CatalogNewTabPageAdPayloadInfo(); - - bool operator==(const CatalogNewTabPageAdPayloadInfo&) const = default; - - std::string company_name; - GURL image_url; - std::string alt; - GURL target_url; - CatalogNewTabPageAdWallpaperList wallpapers; -}; - -} // namespace brave_ads - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_PAYLOAD_INFO_H_ diff --git a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_focal_point_info.h b/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_focal_point_info.h deleted file mode 100644 index 2bb76d752223..000000000000 --- a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_focal_point_info.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ - -namespace brave_ads { - -struct CatalogNewTabPageAdWallpaperFocalPointInfo final { - bool operator==(const CatalogNewTabPageAdWallpaperFocalPointInfo&) const = - default; - - int x = 0; - int y = 0; -}; - -} // namespace brave_ads - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ diff --git a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.cc b/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.cc deleted file mode 100644 index 57d984452c98..000000000000 --- a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 2024 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.h" - -namespace brave_ads { - -CatalogNewTabPageAdWallpaperInfo::CatalogNewTabPageAdWallpaperInfo() = default; - -CatalogNewTabPageAdWallpaperInfo::CatalogNewTabPageAdWallpaperInfo( - const CatalogNewTabPageAdWallpaperInfo& other) = default; - -CatalogNewTabPageAdWallpaperInfo& CatalogNewTabPageAdWallpaperInfo::operator=( - const CatalogNewTabPageAdWallpaperInfo& other) = default; - -CatalogNewTabPageAdWallpaperInfo::CatalogNewTabPageAdWallpaperInfo( - CatalogNewTabPageAdWallpaperInfo&& other) noexcept = default; - -CatalogNewTabPageAdWallpaperInfo& CatalogNewTabPageAdWallpaperInfo::operator=( - CatalogNewTabPageAdWallpaperInfo&& other) noexcept = default; - -CatalogNewTabPageAdWallpaperInfo::~CatalogNewTabPageAdWallpaperInfo() = default; - -} // namespace brave_ads diff --git a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.h b/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.h deleted file mode 100644 index 8d499359a69e..000000000000 --- a/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ - -#include - -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_focal_point_info.h" -#include "brave/components/brave_ads/core/public/serving/targeting/condition_matcher/condition_matcher_util.h" -#include "url/gurl.h" - -namespace brave_ads { - -struct CatalogNewTabPageAdWallpaperInfo final { - CatalogNewTabPageAdWallpaperInfo(); - - CatalogNewTabPageAdWallpaperInfo(const CatalogNewTabPageAdWallpaperInfo&); - CatalogNewTabPageAdWallpaperInfo& operator=( - const CatalogNewTabPageAdWallpaperInfo&); - - CatalogNewTabPageAdWallpaperInfo(CatalogNewTabPageAdWallpaperInfo&&) noexcept; - CatalogNewTabPageAdWallpaperInfo& operator=( - CatalogNewTabPageAdWallpaperInfo&&) noexcept; - - ~CatalogNewTabPageAdWallpaperInfo(); - - bool operator==(const CatalogNewTabPageAdWallpaperInfo&) const = default; - - GURL image_url; - CatalogNewTabPageAdWallpaperFocalPointInfo focal_point; - ConditionMatcherMap condition_matchers; -}; - -using CatalogNewTabPageAdWallpaperList = - std::vector; - -} // namespace brave_ads - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CATALOG_CAMPAIGN_CREATIVE_SET_CREATIVE_NEW_TAB_PAGE_AD_CATALOG_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ diff --git a/components/brave_ads/core/internal/catalog/catalog_url_request_json_reader.cc b/components/brave_ads/core/internal/catalog/catalog_url_request_json_reader.cc index 0bd2c3fa7bd7..4d7660aa1252 100644 --- a/components/brave_ads/core/internal/catalog/catalog_url_request_json_reader.cc +++ b/components/brave_ads/core/internal/catalog/catalog_url_request_json_reader.cc @@ -11,7 +11,6 @@ #include "brave/components/brave_ads/core/internal/ads_client/ads_client_util.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/catalog_campaign_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_conversion_info.h" -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.h" #include "brave/components/brave_ads/core/internal/catalog/catalog_info.h" #include "brave/components/brave_ads/core/internal/common/logging_util.h" #include "brave/components/brave_ads/core/internal/common/url/url_util.h" @@ -301,103 +300,6 @@ std::optional ReadCatalogImpl(const std::string& json) { creative_set.conversions.cend()); creative_set.creative_inline_content_ads.push_back(creative); - } else if (code == "new_tab_page_all_v1") { - CatalogCreativeNewTabPageAdInfo creative; - - creative.instance_id = creative_instance_id; - - // Type - creative.type.code = code; - creative.type.name = type["name"].GetString(); - creative.type.platform = type["platform"].GetString(); - creative.type.version = type["version"].GetInt(); - - // Payload - const auto& payload = creative_node["payload"].GetObject(); - const auto& logo = payload["logo"].GetObject(); - creative.payload.company_name = logo["companyName"].GetString(); - creative.payload.image_url = GURL(logo["imageUrl"].GetString()); - if (!ShouldSupportUrl(creative.payload.image_url)) { - BLOG(1, "Image URL for creative instance id " - << creative_instance_id << " is unsupported"); - continue; - } - creative.payload.alt = logo["alt"].GetString(); - creative.payload.target_url = - GURL(logo["destinationUrl"].GetString()); - if (!ShouldSupportUrl(creative.payload.target_url)) { - BLOG(1, "Target URL for creative instance id " - << creative_instance_id << " is unsupported"); - continue; - } - - creative_set.conversions.erase( - base::ranges::remove_if( - creative_set.conversions, - [&creative_set, - &creative](const CatalogConversionInfo& conversion) { - const GURL conversion_url_pattern = - GURL(conversion.url_pattern); - return conversion.creative_set_id == creative_set.id && - (!ShouldSupportUrl(conversion_url_pattern) || - !SameDomainOrHost(creative.payload.target_url, - conversion_url_pattern)); - }), - creative_set.conversions.cend()); - - for (const auto& wallpaper_node : payload["wallpapers"].GetArray()) { - CatalogNewTabPageAdWallpaperInfo wallpaper; - std::string image_url = wallpaper_node["imageUrl"].GetString(); - // SmartNTTs are targeted locally by the browser and only shown to - // users if the configured conditions match. Non-smart capable - // browsers that predate the introduction of this feature should - // never show these NTTs. To enforce this, we prepend `[SmartNTT]` - // to the `imageURL`, causing non-smart capable browsers to discard - // the wallpaper due to an invalid URL. Once we transition away from - // NTT in the catalog and come up with a new versionable JSON - // schema, we can remove this. - constexpr char kSmartNTTPrefix[] = "[SmartNTT]"; - if (image_url.starts_with(kSmartNTTPrefix)) { - image_url = - image_url.substr(/*pos=*/std::strlen(kSmartNTTPrefix)); - } - wallpaper.image_url = GURL(image_url); - if (!ShouldSupportUrl(wallpaper.image_url)) { - BLOG(1, "Image URL for creative instance id " - << creative_instance_id << " is unsupported"); - continue; - } - wallpaper.focal_point = CatalogNewTabPageAdWallpaperFocalPointInfo{ - .x = wallpaper_node["focalPoint"]["x"].GetInt(), - .y = wallpaper_node["focalPoint"]["y"].GetInt()}; - - // For Rewards users, these matchers should be placed in the catalog - // under "wallpapers" with the "imageUrl" prefixed with "[SmartNTT]" - // for backwards compatibility, where legacy browsers will discard - // these wallpapers due to an invalid URL. - if (wallpaper_node.HasMember("conditionMatchers")) { - if (wallpaper_node["conditionMatchers"].IsArray()) { - for (const auto& condition_matchers_node : - wallpaper_node["conditionMatchers"].GetArray()) { - if (condition_matchers_node["prefPath"].IsString() && - condition_matchers_node["condition"].IsString()) { - wallpaper.condition_matchers.emplace( - condition_matchers_node["prefPath"].GetString(), - condition_matchers_node["condition"].GetString()); - } - } - } - } - creative.payload.wallpapers.push_back(wallpaper); - } - - if (creative.payload.wallpapers.empty()) { - BLOG(1, "Failed to parse wallpapers for creative instance id " - << creative_instance_id); - continue; - } - - creative_set.creative_new_tab_page_ads.push_back(creative); } else if (code == "promoted_content_all_v1") { CatalogCreativePromotedContentAdInfo creative; diff --git a/components/brave_ads/core/internal/catalog/catalog_url_request_json_reader_unittest.cc b/components/brave_ads/core/internal/catalog/catalog_url_request_json_reader_unittest.cc index fb2d463c93df..f79e93664cb2 100644 --- a/components/brave_ads/core/internal/catalog/catalog_url_request_json_reader_unittest.cc +++ b/components/brave_ads/core/internal/catalog/catalog_url_request_json_reader_unittest.cc @@ -14,9 +14,6 @@ #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/catalog_segment_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/catalog_type_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/inline_content_ad/catalog_creative_inline_content_ad_info.h" -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_creative_new_tab_page_ad_info.h" -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_focal_point_info.h" -#include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/new_tab_page_ad/catalog_new_tab_page_ad_wallpaper_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/notification_ad/catalog_creative_notification_ad_info.h" #include "brave/components/brave_ads/core/internal/catalog/campaign/creative_set/creative/promoted_content_ad/catalog_creative_promoted_content_ad_info.h" #include "brave/components/brave_ads/core/internal/catalog/catalog_info.h" @@ -80,33 +77,6 @@ CatalogCampaignInfo BuildCatalogCampaign1() { GURL("https://brave.com/1/notification_ad"); catalog_creative_notification_ads.push_back(catalog_creative_notification_ad); - // Creative New Tab Page Ads - CatalogCreativeNewTabPageAdList catalog_creative_new_tab_page_ads; - - CatalogCreativeNewTabPageAdInfo catalog_creative_new_tab_page_ad; - catalog_creative_new_tab_page_ad.instance_id = - "7ff400b9-7f8a-46a8-89f1-cb386612edcf"; - CatalogTypeInfo catalog_type_new_tab_page_ad; - catalog_type_new_tab_page_ad.code = "new_tab_page_all_v1"; - catalog_type_new_tab_page_ad.name = "new_tab_page"; - catalog_type_new_tab_page_ad.platform = "all"; - catalog_type_new_tab_page_ad.version = 1; - catalog_creative_new_tab_page_ad.type = catalog_type_new_tab_page_ad; - catalog_creative_new_tab_page_ad.payload.company_name = "New Tab Page 1"; - catalog_creative_new_tab_page_ad.payload.image_url = - GURL("https://brave.com/1/test.jpg"); - catalog_creative_new_tab_page_ad.payload.alt = - "Test New Tab Page Ad Campaign 1"; - catalog_creative_new_tab_page_ad.payload.target_url = - GURL("https://brave.com/1/new_tab_page_ad"); - CatalogNewTabPageAdWallpaperInfo wallpaper; - wallpaper.image_url = GURL("https://brave.com/1/test2.jpg"); - wallpaper.focal_point = - CatalogNewTabPageAdWallpaperFocalPointInfo{.x = 1'200, .y = 1'400}; - catalog_creative_new_tab_page_ad.payload.wallpapers.push_back(wallpaper); - - catalog_creative_new_tab_page_ads.push_back(catalog_creative_new_tab_page_ad); - // Creative Promoted Content Ads CatalogCreativePromotedContentAdList catalog_creative_promoted_content_ads; @@ -180,8 +150,6 @@ CatalogCampaignInfo BuildCatalogCampaign1() { catalog_creative_notification_ads; catalog_creative_set.creative_inline_content_ads = catalog_creative_inline_content_ads; - catalog_creative_set.creative_new_tab_page_ads = - catalog_creative_new_tab_page_ads; catalog_creative_set.creative_promoted_content_ads = catalog_creative_promoted_content_ads; catalog_creative_set.conversions = catalog_conversions; @@ -269,34 +237,6 @@ CatalogCampaignInfo BuildCatalogCampaign2() { GURL("https://brave.com/2/notification_ad"); catalog_creative_notification_ads.push_back(catalog_creative_notification_ad); - // Creative New Tab Page Ads - CatalogCreativeNewTabPageAdList catalog_creative_new_tab_page_ads; - - CatalogCreativeNewTabPageAdInfo catalog_creative_new_tab_page_ad; - catalog_creative_new_tab_page_ad.instance_id = - "3dfe54d0-80b7-48d7-9bcc-3c77a912f583"; - CatalogTypeInfo catalog_type_new_tab_page_ad; - catalog_type_new_tab_page_ad.code = "new_tab_page_all_v1"; - catalog_type_new_tab_page_ad.name = "new_tab_page"; - catalog_type_new_tab_page_ad.platform = "all"; - catalog_type_new_tab_page_ad.version = 1; - catalog_creative_new_tab_page_ad.type = catalog_type_new_tab_page_ad; - catalog_creative_new_tab_page_ad.payload.company_name = "New Tab Page 2"; - catalog_creative_new_tab_page_ad.payload.image_url = - GURL("https://brave.com/2/test.jpg"); - catalog_creative_new_tab_page_ad.payload.alt = - "Test New Tab Page Ad Campaign 2"; - catalog_creative_new_tab_page_ad.payload.target_url = - GURL("https://brave.com/2/new_tab_page_ad"); - CatalogNewTabPageAdWallpaperInfo wallpaper; - wallpaper.image_url = GURL("https://brave.com/2/test2.jpg"); - wallpaper.focal_point = - CatalogNewTabPageAdWallpaperFocalPointInfo{.x = 1'000, .y = 1'200}; - wallpaper.condition_matchers.emplace("brave.today.opted_in", "1"); - catalog_creative_new_tab_page_ad.payload.wallpapers.push_back(wallpaper); - - catalog_creative_new_tab_page_ads.push_back(catalog_creative_new_tab_page_ad); - // Creative Promoted Content Ads CatalogCreativePromotedContentAdList catalog_creative_promoted_content_ads; @@ -367,8 +307,6 @@ CatalogCampaignInfo BuildCatalogCampaign2() { catalog_creative_set.oses = catalog_oses; catalog_creative_set.creative_notification_ads = catalog_creative_notification_ads; - catalog_creative_set.creative_new_tab_page_ads = - catalog_creative_new_tab_page_ads; catalog_creative_set.creative_promoted_content_ads = catalog_creative_promoted_content_ads; catalog_creative_set.creative_inline_content_ads = diff --git a/components/brave_ads/core/internal/catalog/catalog_util.cc b/components/brave_ads/core/internal/catalog/catalog_util.cc index 99d3e28dc822..5e57a4501771 100644 --- a/components/brave_ads/core/internal/catalog/catalog_util.cc +++ b/components/brave_ads/core/internal/catalog/catalog_util.cc @@ -5,53 +5,132 @@ #include "brave/components/brave_ads/core/internal/catalog/catalog_util.h" +#include + +#include "base/functional/bind.h" #include "base/time/time.h" -#include "brave/components/brave_ads/core/internal/account/deposits/deposits_database_util.h" #include "brave/components/brave_ads/core/internal/catalog/catalog_feature.h" #include "brave/components/brave_ads/core/internal/catalog/catalog_info.h" -#include "brave/components/brave_ads/core/internal/creatives/campaigns_database_util.h" +#include "brave/components/brave_ads/core/internal/common/database/database_transaction_util.h" +#include "brave/components/brave_ads/core/internal/common/logging_util.h" #include "brave/components/brave_ads/core/internal/creatives/conversions/creative_set_conversion_database_table_util.h" -#include "brave/components/brave_ads/core/internal/creatives/creative_ads_database_util.h" #include "brave/components/brave_ads/core/internal/creatives/creatives_builder.h" #include "brave/components/brave_ads/core/internal/creatives/creatives_info.h" -#include "brave/components/brave_ads/core/internal/creatives/dayparts_database_util.h" -#include "brave/components/brave_ads/core/internal/creatives/geo_targets_database_util.h" #include "brave/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.h" #include "brave/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.h" #include "brave/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.h" -#include "brave/components/brave_ads/core/internal/creatives/segments_database_util.h" #include "brave/components/brave_ads/core/internal/prefs/pref_util.h" +#include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" +#include "brave/components/brave_ads/core/public/ads_client/ads_client_callback.h" #include "brave/components/brave_ads/core/public/prefs/pref_names.h" namespace brave_ads { namespace { -void Delete() { - database::DeleteCampaigns(); - database::DeleteCreativeNotificationAds(); - database::DeleteCreativeInlineContentAds(); - database::DeleteCreativeNewTabPageAds(); - database::DeleteCreativeNewTabPageAdWallpapers(); - database::DeleteCreativePromotedContentAds(); - database::DeleteCreativeAds(); - database::DeleteSegments(); - database::DeleteGeoTargets(); - database::DeleteDayparts(); -} - -void PurgeExpired() { - database::PurgeExpiredCreativeSetConversions(); - database::PurgeExpiredDeposits(); +void Delete(ResultCallback callback) { + mojom::DBTransactionInfoPtr mojom_db_transaction = + mojom::DBTransactionInfo::New(); + + // Remove catalog data not linked to new tab page ads. New tab page ads are + // provided by component resources and will be purged on component update. + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + campaigns + WHERE + id NOT IN ( + SELECT + DISTINCT campaign_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + geo_targets + WHERE + campaign_id NOT IN ( + SELECT + DISTINCT campaign_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + dayparts + WHERE + campaign_id NOT IN ( + SELECT + DISTINCT campaign_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + segments + WHERE + creative_set_id NOT IN ( + SELECT + DISTINCT creative_set_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + creative_ads + WHERE + creative_instance_id NOT IN ( + SELECT + DISTINCT creative_instance_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + creative_ad_notifications + WHERE + creative_instance_id NOT IN ( + SELECT + DISTINCT creative_instance_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + creative_inline_content_ads + WHERE + creative_instance_id NOT IN ( + SELECT + DISTINCT creative_instance_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + creative_promoted_content_ads + WHERE + creative_instance_id NOT IN ( + SELECT + DISTINCT creative_instance_id + FROM + creative_new_tab_page_ads + );)"); + + database::RunDBTransaction(FROM_HERE, std::move(mojom_db_transaction), + std::move(callback)); } -} // namespace - -void SaveCatalog(const CatalogInfo& catalog) { - Delete(); - - PurgeExpired(); +void SaveCatalogCallback(const CatalogInfo& catalog, bool success) { + if (!success) { + return BLOG(0, "Failed to save catalog"); + } SetCatalogId(catalog.id); SetCatalogVersion(catalog.version); @@ -60,18 +139,29 @@ void SaveCatalog(const CatalogInfo& catalog) { const CreativesInfo creatives = BuildCreatives(catalog); database::SaveCreativeNotificationAds(creatives.notification_ads); database::SaveCreativeInlineContentAds(creatives.inline_content_ads); - database::SaveCreativeNewTabPageAds(creatives.new_tab_page_ads); database::SaveCreativePromotedContentAds(creatives.promoted_content_ads); database::SaveCreativeSetConversions(creatives.conversions); } -void ResetCatalog() { +void ResetCatalogCallback(bool success) { + if (!success) { + return BLOG(0, "Failed to reset catalog"); + } + ClearProfilePref(prefs::kCatalogId); ClearProfilePref(prefs::kCatalogVersion); ClearProfilePref(prefs::kCatalogPing); ClearProfilePref(prefs::kCatalogLastUpdated); +} + +} // namespace - Delete(); +void SaveCatalog(const CatalogInfo& catalog) { + Delete(base::BindOnce(&SaveCatalogCallback, catalog)); +} + +void ResetCatalog() { + Delete(base::BindOnce(&ResetCatalogCallback)); } std::string GetCatalogId() { diff --git a/components/brave_ads/core/internal/creatives/campaigns_database_table.cc b/components/brave_ads/core/internal/creatives/campaigns_database_table.cc index 432a6fdcd3e0..96ba4da26866 100644 --- a/components/brave_ads/core/internal/creatives/campaigns_database_table.cc +++ b/components/brave_ads/core/internal/creatives/campaigns_database_table.cc @@ -98,8 +98,8 @@ void Campaigns::Migrate(const mojom::DBTransactionInfoPtr& mojom_db_transaction, CHECK(mojom_db_transaction); switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -107,12 +107,14 @@ void Campaigns::Migrate(const mojom::DBTransactionInfoPtr& mojom_db_transaction, /////////////////////////////////////////////////////////////////////////////// -void Campaigns::MigrateToV45( +void Campaigns::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // It is safe to recreate the table because it will be repopulated after + // downloading the catalog post-migration. However, after this migration, we + // should not drop the table as it will be used to store data for non-catalog + // ad units and to maintain relationships with other tables. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } diff --git a/components/brave_ads/core/internal/creatives/campaigns_database_table.h b/components/brave_ads/core/internal/creatives/campaigns_database_table.h index 412989309c0b..0ddcf50b3023 100644 --- a/components/brave_ads/core/internal/creatives/campaigns_database_table.h +++ b/components/brave_ads/core/internal/creatives/campaigns_database_table.h @@ -29,7 +29,7 @@ class Campaigns final : public TableInterface { int to_version) override; private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); std::string BuildInsertSql(const mojom::DBActionInfoPtr& mojom_db_action, const CreativeAdList& creative_ads) const; diff --git a/components/brave_ads/core/internal/creatives/creative_ad_info.cc b/components/brave_ads/core/internal/creatives/creative_ad_info.cc index 2e6838020aac..75d73b38212d 100644 --- a/components/brave_ads/core/internal/creatives/creative_ad_info.cc +++ b/components/brave_ads/core/internal/creatives/creative_ad_info.cc @@ -39,6 +39,7 @@ bool CreativeAdInfo::operator==(const CreativeAdInfo& other) const { std::numeric_limits::epsilon()) && split_test_group == other.split_test_group && segment == other.segment && geo_targets == other.geo_targets && + condition_matchers == other.condition_matchers && target_url == other.target_url && dayparts == other.dayparts; } diff --git a/components/brave_ads/core/internal/creatives/creative_ad_info.h b/components/brave_ads/core/internal/creatives/creative_ad_info.h index 968f8f071713..5a80520c2f0c 100644 --- a/components/brave_ads/core/internal/creatives/creative_ad_info.h +++ b/components/brave_ads/core/internal/creatives/creative_ad_info.h @@ -12,6 +12,7 @@ #include "base/containers/flat_set.h" #include "base/time/time.h" #include "brave/components/brave_ads/core/internal/creatives/creative_daypart_info.h" +#include "brave/components/brave_ads/core/public/serving/targeting/condition_matcher/condition_matcher_util.h" #include "url/gurl.h" namespace brave_ads { @@ -48,6 +49,7 @@ struct CreativeAdInfo { std::string split_test_group; CreativeDaypartList dayparts; base::flat_set geo_targets; + ConditionMatcherMap condition_matchers; GURL target_url; }; diff --git a/components/brave_ads/core/internal/creatives/creative_ads_database_table.cc b/components/brave_ads/core/internal/creatives/creative_ads_database_table.cc index 7e2af8d86843..37edb1b87602 100644 --- a/components/brave_ads/core/internal/creatives/creative_ads_database_table.cc +++ b/components/brave_ads/core/internal/creatives/creative_ads_database_table.cc @@ -14,11 +14,11 @@ #include "base/functional/bind.h" #include "base/location.h" #include "base/strings/strcat.h" -#include "base/strings/string_util.h" #include "brave/components/brave_ads/core/internal/common/database/database_column_util.h" #include "brave/components/brave_ads/core/internal/common/database/database_table_util.h" #include "brave/components/brave_ads/core/internal/common/database/database_transaction_util.h" #include "brave/components/brave_ads/core/internal/common/logging_util.h" +#include "brave/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.h" #include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" #include "url/gurl.h" @@ -43,6 +43,7 @@ void BindColumnTypes(const mojom::DBActionInfoPtr& mojom_db_action) { mojom::DBBindColumnType::kInt, // total_max mojom::DBBindColumnType::kDouble, // value mojom::DBBindColumnType::kString, // split_test_group + mojom::DBBindColumnType::kString, // condition_matchers mojom::DBBindColumnType::kString // target_url }; } @@ -65,6 +66,8 @@ size_t BindColumns(const mojom::DBActionInfoPtr& mojom_db_action, BindColumnInt(mojom_db_action, index++, creative_ad.total_max); BindColumnDouble(mojom_db_action, index++, creative_ad.value); BindColumnString(mojom_db_action, index++, creative_ad.split_test_group); + BindColumnString(mojom_db_action, index++, + ConditionMatchersToString(creative_ad.condition_matchers)); BindColumnString(mojom_db_action, index++, creative_ad.target_url.spec()); ++row_count; @@ -85,8 +88,10 @@ CreativeAdInfo FromMojomRow(const mojom::DBRowInfoPtr& mojom_db_row) { creative_ad.per_month = ColumnInt(mojom_db_row, 4); creative_ad.total_max = ColumnInt(mojom_db_row, 5); creative_ad.value = ColumnDouble(mojom_db_row, 6); - creative_ad.split_test_group = ColumnString(mojom_db_row, 13); - creative_ad.target_url = GURL(ColumnString(mojom_db_row, 7)); + creative_ad.split_test_group = ColumnString(mojom_db_row, 7); + creative_ad.condition_matchers = + StringToConditionMatchers(ColumnString(mojom_db_row, 8)); + creative_ad.target_url = GURL(ColumnString(mojom_db_row, 9)); return creative_ad; } @@ -239,6 +244,7 @@ void CreativeAds::Create( total_max INTEGER NOT NULL DEFAULT 0, value DOUBLE NOT NULL DEFAULT 0, split_test_group TEXT, + condition_matchers TEXT NOT NULL, target_url TEXT NOT NULL );)"); } @@ -249,8 +255,8 @@ void CreativeAds::Migrate( CHECK(mojom_db_transaction); switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -258,12 +264,14 @@ void CreativeAds::Migrate( /////////////////////////////////////////////////////////////////////////////// -void CreativeAds::MigrateToV45( +void CreativeAds::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // It is safe to recreate the table because it will be repopulated after + // downloading the catalog post-migration. However, after this migration, we + // should not drop the table as it will be used to store data for non-catalog + // ad units and to maintain relationships with other tables. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } @@ -287,10 +295,11 @@ std::string CreativeAds::BuildInsertSql( total_max, value, split_test_group, + condition_matchers, target_url ) VALUES $2;)", {GetTableName(), - BuildBindColumnPlaceholders(/*column_count=*/9, row_count)}, + BuildBindColumnPlaceholders(/*column_count=*/10, row_count)}, nullptr); } diff --git a/components/brave_ads/core/internal/creatives/creative_ads_database_table.h b/components/brave_ads/core/internal/creatives/creative_ads_database_table.h index fe39cf5475b7..baa8c776dcac 100644 --- a/components/brave_ads/core/internal/creatives/creative_ads_database_table.h +++ b/components/brave_ads/core/internal/creatives/creative_ads_database_table.h @@ -38,7 +38,7 @@ class CreativeAds final : public TableInterface { int to_version) override; private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); std::string BuildInsertSql(const mojom::DBActionInfoPtr& mojom_db_action, const CreativeAdList& creative_ads) const; diff --git a/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.cc b/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.cc new file mode 100644 index 000000000000..99e945991d54 --- /dev/null +++ b/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.cc @@ -0,0 +1,67 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.h" + +#include + +#include "base/base64.h" +#include "base/strings/strcat.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" + +namespace brave_ads::database::table { + +std::string ConditionMatchersToString( + const ConditionMatcherMap& condition_matchers) { + std::vector condition_matchers_as_string; + condition_matchers_as_string.reserve(condition_matchers.size()); + + for (const auto& [pref_name, condition] : condition_matchers) { + // We base64 encode the `pref_name` and `condition` to avoid any issues with + // pref paths and conditions that contain either `|` or `;`. + + const std::string condition_matcher = base::StrCat( + {base::Base64Encode(pref_name), "|", base::Base64Encode(condition)}); + condition_matchers_as_string.push_back(condition_matcher); + } + + return base::JoinString(condition_matchers_as_string, ";"); +} + +ConditionMatcherMap StringToConditionMatchers(const std::string& value) { + const std::vector condition_matchers_as_string = + base::SplitString(value, ";", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + + ConditionMatcherMap condition_matchers; + for (const auto& condition_matcher_as_string : condition_matchers_as_string) { + const std::vector condition_matcher = + base::SplitString(condition_matcher_as_string, "|", + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + if (condition_matcher.size() != 2) { + // Malfomed condition matcher. + continue; + } + + std::string pref_path; + if (!base::Base64Decode(condition_matcher[0], &pref_path)) { + // Malfomed condition matcher. + continue; + } + + std::string condition; + if (!base::Base64Decode(condition_matcher[1], &condition)) { + // Malfomed condition matcher. + continue; + } + + condition_matchers.emplace(pref_path, condition); + } + + return condition_matchers; +} + +} // namespace brave_ads::database::table diff --git a/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.h b/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.h new file mode 100644 index 000000000000..685928c2d320 --- /dev/null +++ b/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_CREATIVE_ADS_DATABASE_TABLE_UTIL_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_CREATIVE_ADS_DATABASE_TABLE_UTIL_H_ + +#include + +#include "brave/components/brave_ads/core/public/serving/targeting/condition_matcher/condition_matcher_util.h" + +namespace brave_ads::database::table { + +std::string ConditionMatchersToString( + const ConditionMatcherMap& condition_matchers); + +ConditionMatcherMap StringToConditionMatchers(const std::string& value); + +} // namespace brave_ads::database::table + +#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_CREATIVE_ADS_DATABASE_TABLE_UTIL_H_ diff --git a/components/brave_ads/core/internal/creatives/creative_ads_database_table_util_unittest.cc b/components/brave_ads/core/internal/creatives/creative_ads_database_table_util_unittest.cc new file mode 100644 index 000000000000..65d49b3cdd9d --- /dev/null +++ b/components/brave_ads/core/internal/creatives/creative_ads_database_table_util_unittest.cc @@ -0,0 +1,22 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.h" + +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=BraveAds* + +namespace brave_ads::database::table { + +TEST(BraveAdsCreativeAdsDatabaseTableUtilTest, ConditionMatchersToString) { + FAIL(); +} + +TEST(BraveAdsCreativeAdsDatabaseTableUtilTest, StringToConditionMatchers) { + FAIL(); +} + +} // namespace brave_ads::database::table diff --git a/components/brave_ads/core/internal/creatives/creative_ads_database_util.cc b/components/brave_ads/core/internal/creatives/creative_ads_database_util.cc deleted file mode 100644 index 61b18f6ee643..000000000000 --- a/components/brave_ads/core/internal/creatives/creative_ads_database_util.cc +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/creatives/creative_ads_database_util.h" - -#include "base/functional/bind.h" -#include "brave/components/brave_ads/core/internal/common/logging_util.h" -#include "brave/components/brave_ads/core/internal/creatives/creative_ads_database_table.h" - -namespace brave_ads::database { - -void DeleteCreativeAds() { - const table::CreativeAds database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete creative ads"); - } - })); -} - -} // namespace brave_ads::database diff --git a/components/brave_ads/core/internal/creatives/creative_ads_database_util.h b/components/brave_ads/core/internal/creatives/creative_ads_database_util.h deleted file mode 100644 index 97897729535d..000000000000 --- a/components/brave_ads/core/internal/creatives/creative_ads_database_util.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_CREATIVE_ADS_DATABASE_UTIL_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_CREATIVE_ADS_DATABASE_UTIL_H_ - -namespace brave_ads::database { - -void DeleteCreativeAds(); - -} // namespace brave_ads::database - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_CREATIVE_ADS_DATABASE_UTIL_H_ diff --git a/components/brave_ads/core/internal/creatives/creatives_builder.cc b/components/brave_ads/core/internal/creatives/creatives_builder.cc index 126869ec4611..1cf9411fe61f 100644 --- a/components/brave_ads/core/internal/creatives/creatives_builder.cc +++ b/components/brave_ads/core/internal/creatives/creatives_builder.cc @@ -20,9 +20,6 @@ #include "brave/components/brave_ads/core/internal/creatives/creative_daypart_info.h" #include "brave/components/brave_ads/core/internal/creatives/creatives_info.h" #include "brave/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ad_info.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_focal_point_info.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.h" #include "brave/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ad_info.h" #include "brave/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ad_info.h" @@ -199,85 +196,6 @@ CreativesInfo BuildCreatives(const CatalogInfo& catalog) { } } - // New tab page ad creatives - for (const auto& creative : creative_set.creative_new_tab_page_ads) { - CreativeNewTabPageAdInfo creative_ad; - creative_ad.creative_instance_id = creative.instance_id; - creative_ad.creative_set_id = creative_set.id; - creative_ad.campaign_id = campaign.id; - creative_ad.advertiser_id = campaign.advertiser_id; - if (!base::Time::FromUTCString(campaign.start_at.c_str(), - &creative_ad.start_at)) { - BLOG(1, "Campaign id " << campaign.id - << " has an invalid start at time"); - } - if (!base::Time::FromUTCString(campaign.end_at.c_str(), - &creative_ad.end_at)) { - BLOG(1, - "Campaign id " << campaign.id << " has an invalid end at time"); - } - creative_ad.daily_cap = campaign.daily_cap; - creative_ad.priority = campaign.priority; - creative_ad.pass_through_rate = campaign.pass_through_rate; - creative_ad.per_day = creative_set.per_day; - creative_ad.per_week = creative_set.per_week; - creative_ad.per_month = creative_set.per_month; - creative_ad.total_max = creative_set.total_max; - creative_ad.value = creative_set.value; - creative_ad.split_test_group = creative_set.split_test_group; - creative_ad.dayparts = dayparts; - creative_ad.geo_targets = geo_targets; - creative_ad.target_url = creative.payload.target_url; - - creative_ad.company_name = creative.payload.company_name; - creative_ad.image_url = creative.payload.image_url; - creative_ad.alt = creative.payload.alt; - - CHECK(!creative.payload.wallpapers.empty()); - for (const auto& catalog_new_tab_page_ad_wallpaper : - creative.payload.wallpapers) { - CreativeNewTabPageAdWallpaperInfo wallpaper; - wallpaper.image_url = catalog_new_tab_page_ad_wallpaper.image_url; - wallpaper.focal_point = CreativeNewTabPageAdWallpaperFocalPointInfo{ - .x = catalog_new_tab_page_ad_wallpaper.focal_point.x, - .y = catalog_new_tab_page_ad_wallpaper.focal_point.y}; - wallpaper.condition_matchers = - catalog_new_tab_page_ad_wallpaper.condition_matchers; - creative_ad.wallpapers.push_back(wallpaper); - } - - // Segments - for (const auto& segment : creative_set.segments) { - const std::string segment_name = base::ToLowerASCII(segment.name); - CHECK(!segment_name.empty()); - - std::vector segment_name_hierarchy = - base::SplitString(segment_name, "-", base::KEEP_WHITESPACE, - base::SPLIT_WANT_NONEMPTY); - - if (segment_name_hierarchy.empty()) { - BLOG(1, "creative set id " << creative_set.id - << " segment name should not be empty"); - - continue; - } - - creative_ad.segment = segment_name; - creatives.new_tab_page_ads.push_back(creative_ad); - ++entries; - - const std::string& top_level_segment_name = - segment_name_hierarchy.front(); - CHECK(!top_level_segment_name.empty()); - - if (top_level_segment_name != segment_name) { - creative_ad.segment = top_level_segment_name; - creatives.new_tab_page_ads.push_back(creative_ad); - ++entries; - } - } - } - // Promoted content ad creatives for (const auto& creative : creative_set.creative_promoted_content_ads) { CreativePromotedContentAdInfo creative_ad; diff --git a/components/brave_ads/core/internal/creatives/dayparts_database_table.cc b/components/brave_ads/core/internal/creatives/dayparts_database_table.cc index 96c162e629ab..f968d6027629 100644 --- a/components/brave_ads/core/internal/creatives/dayparts_database_table.cc +++ b/components/brave_ads/core/internal/creatives/dayparts_database_table.cc @@ -97,8 +97,8 @@ void Dayparts::Migrate(const mojom::DBTransactionInfoPtr& mojom_db_transaction, CHECK(mojom_db_transaction); switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -106,12 +106,14 @@ void Dayparts::Migrate(const mojom::DBTransactionInfoPtr& mojom_db_transaction, /////////////////////////////////////////////////////////////////////////////// -void Dayparts::MigrateToV45( +void Dayparts::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // It is safe to recreate the table because it will be repopulated after + // downloading the catalog post-migration. However, after this migration, we + // should not drop the table as it will be used to store data for non-catalog + // ads units and to maintain relationships with other tables. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } diff --git a/components/brave_ads/core/internal/creatives/dayparts_database_table.h b/components/brave_ads/core/internal/creatives/dayparts_database_table.h index 106ba925a494..effef51a217c 100644 --- a/components/brave_ads/core/internal/creatives/dayparts_database_table.h +++ b/components/brave_ads/core/internal/creatives/dayparts_database_table.h @@ -29,7 +29,7 @@ class Dayparts final : public TableInterface { int to_version) override; private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); std::string BuildInsertSql(const mojom::DBActionInfoPtr& mojom_db_action, const CreativeAdList& creative_ads) const; diff --git a/components/brave_ads/core/internal/creatives/dayparts_database_util.cc b/components/brave_ads/core/internal/creatives/dayparts_database_util.cc deleted file mode 100644 index b20c1a38009b..000000000000 --- a/components/brave_ads/core/internal/creatives/dayparts_database_util.cc +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/creatives/dayparts_database_util.h" - -#include "base/functional/bind.h" -#include "brave/components/brave_ads/core/internal/common/logging_util.h" -#include "brave/components/brave_ads/core/internal/creatives/dayparts_database_table.h" - -namespace brave_ads::database { - -void DeleteDayparts() { - const table::Dayparts database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete dayparts"); - } - })); -} - -} // namespace brave_ads::database diff --git a/components/brave_ads/core/internal/creatives/dayparts_database_util.h b/components/brave_ads/core/internal/creatives/dayparts_database_util.h deleted file mode 100644 index 4658b11e0459..000000000000 --- a/components/brave_ads/core/internal/creatives/dayparts_database_util.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_DAYPARTS_DATABASE_UTIL_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_DAYPARTS_DATABASE_UTIL_H_ - -namespace brave_ads::database { - -void DeleteDayparts(); - -} // namespace brave_ads::database - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_DAYPARTS_DATABASE_UTIL_H_ diff --git a/components/brave_ads/core/internal/creatives/geo_targets_database_table.cc b/components/brave_ads/core/internal/creatives/geo_targets_database_table.cc index b572afc80c4a..480d31a103a2 100644 --- a/components/brave_ads/core/internal/creatives/geo_targets_database_table.cc +++ b/components/brave_ads/core/internal/creatives/geo_targets_database_table.cc @@ -93,8 +93,8 @@ void GeoTargets::Migrate( CHECK(mojom_db_transaction); switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -102,12 +102,14 @@ void GeoTargets::Migrate( /////////////////////////////////////////////////////////////////////////////// -void GeoTargets::MigrateToV45( +void GeoTargets::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // It is safe to recreate the table because it will be repopulated after + // downloading the catalog post-migration. However, after this migration, we + // should not drop the table as it will be used to store data for non-catalog + // ads units and to maintain relationships with other tables. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } diff --git a/components/brave_ads/core/internal/creatives/geo_targets_database_table.h b/components/brave_ads/core/internal/creatives/geo_targets_database_table.h index 631778fa94d3..57d9c83a0547 100644 --- a/components/brave_ads/core/internal/creatives/geo_targets_database_table.h +++ b/components/brave_ads/core/internal/creatives/geo_targets_database_table.h @@ -29,7 +29,7 @@ class GeoTargets final : public TableInterface { int to_version) override; private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); std::string BuildInsertSql(const mojom::DBActionInfoPtr& mojom_db_action, const CreativeAdList& creative_ads) const; diff --git a/components/brave_ads/core/internal/creatives/geo_targets_database_util.cc b/components/brave_ads/core/internal/creatives/geo_targets_database_util.cc deleted file mode 100644 index 311972c7b665..000000000000 --- a/components/brave_ads/core/internal/creatives/geo_targets_database_util.cc +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/creatives/geo_targets_database_util.h" - -#include "base/functional/bind.h" -#include "brave/components/brave_ads/core/internal/common/logging_util.h" -#include "brave/components/brave_ads/core/internal/creatives/geo_targets_database_table.h" - -namespace brave_ads::database { - -void DeleteGeoTargets() { - const table::GeoTargets database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete geo targets"); - } - })); -} - -} // namespace brave_ads::database diff --git a/components/brave_ads/core/internal/creatives/geo_targets_database_util.h b/components/brave_ads/core/internal/creatives/geo_targets_database_util.h deleted file mode 100644 index 4957108a6c92..000000000000 --- a/components/brave_ads/core/internal/creatives/geo_targets_database_util.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_GEO_TARGETS_DATABASE_UTIL_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_GEO_TARGETS_DATABASE_UTIL_H_ - -namespace brave_ads::database { - -void DeleteGeoTargets(); - -} // namespace brave_ads::database - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_GEO_TARGETS_DATABASE_UTIL_H_ diff --git a/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.cc b/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.cc index dc14012a81b8..ed7ba6a0738c 100644 --- a/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.cc +++ b/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.cc @@ -564,8 +564,8 @@ void CreativeInlineContentAds::Migrate( CHECK(mojom_db_transaction); switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -573,12 +573,14 @@ void CreativeInlineContentAds::Migrate( /////////////////////////////////////////////////////////////////////////////// -void CreativeInlineContentAds::MigrateToV45( +void CreativeInlineContentAds::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // Recreating the table is safe because it will be repopulated after + // downloading the catalog post-migration. However, after this migration, we + // should not drop the table as it needs to maintain relationships with other + // tables. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } diff --git a/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.h b/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.h index 0c1b37acc6bd..64aba230986c 100644 --- a/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.h +++ b/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.h @@ -81,7 +81,7 @@ class CreativeInlineContentAds final : public TableInterface { int to_version) override; private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); void Insert(const mojom::DBTransactionInfoPtr& mojom_db_transaction, const CreativeInlineContentAdList& creative_ads); diff --git a/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.cc b/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.cc index 099c9e158183..6f427569e7a5 100644 --- a/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.cc +++ b/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.cc @@ -11,15 +11,6 @@ namespace brave_ads::database { -void DeleteCreativeInlineContentAds() { - const table::CreativeInlineContentAds database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete creative inline content ads"); - } - })); -} - void SaveCreativeInlineContentAds( const CreativeInlineContentAdList& creative_ads) { table::CreativeInlineContentAds database_table; diff --git a/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.h b/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.h index f5db2f74bfc6..1ba5c45cecd7 100644 --- a/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.h +++ b/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_util.h @@ -10,8 +10,6 @@ namespace brave_ads::database { -void DeleteCreativeInlineContentAds(); - void SaveCreativeInlineContentAds( const CreativeInlineContentAdList& creative_ads); diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/README.md b/components/brave_ads/core/internal/creatives/new_tab_page_ads/README.md index 7d0bc560ebb7..99c65aab7131 100644 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/README.md +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/README.md @@ -1,5 +1,5 @@ # New Tab Page Ad Creative -A new tab page ad creative refers to the advertisement's visual and written elements, including image, wallpapers, company name and alt used in the ad. See [ad units](../../ad_units/README.md). +A new tab page ad creative refers to the advertisement's visual and written elements, including company name and alt used in the ad. See [ad units](../../ad_units/README.md). Please add to it! diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h index bb1a8c9547e9..a52357691b56 100644 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h @@ -10,8 +10,6 @@ #include #include "brave/components/brave_ads/core/internal/creatives/creative_ad_info.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.h" -#include "url/gurl.h" namespace brave_ads { @@ -30,9 +28,7 @@ struct CreativeNewTabPageAdInfo final : CreativeAdInfo { bool operator==(const CreativeNewTabPageAdInfo&) const = default; std::string company_name; - GURL image_url; std::string alt; - CreativeNewTabPageAdWallpaperList wallpapers; }; using CreativeNewTabPageAdList = std::vector; diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_test_util.cc b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_test_util.cc index 22f675a12a4e..7137de897f58 100644 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_test_util.cc +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_test_util.cc @@ -9,10 +9,7 @@ #include "brave/components/brave_ads/core/internal/creatives/creative_ad_info.h" #include "brave/components/brave_ads/core/internal/creatives/creative_ad_test_util.h" #include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_focal_point_info.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.h" #include "brave/components/brave_ads/core/internal/segments/segment_test_constants.h" -#include "url/gurl.h" namespace brave_ads::test { @@ -39,17 +36,8 @@ CreativeNewTabPageAdInfo BuildCreativeNewTabPageAd( CreativeNewTabPageAdInfo creative_new_tab_page_ad(creative_ad); creative_new_tab_page_ad.company_name = "Test Ad Company Name"; - creative_new_tab_page_ad.image_url = GURL("https://brave.com/image"); creative_new_tab_page_ad.alt = "Test Ad Alt"; - CreativeNewTabPageAdWallpaperInfo wallpaper; - wallpaper.image_url = GURL("https://brave.com/wallpaper_image"); - CreativeNewTabPageAdWallpaperFocalPointInfo wallpaper_focal_point; - wallpaper_focal_point.x = 1280; - wallpaper_focal_point.y = 720; - wallpaper.focal_point = wallpaper_focal_point; - creative_new_tab_page_ad.wallpapers.push_back(wallpaper); - return creative_new_tab_page_ad; } diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_focal_point_info.h b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_focal_point_info.h deleted file mode 100644 index 3919cb2dcc8f..000000000000 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_focal_point_info.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ - -namespace brave_ads { - -struct CreativeNewTabPageAdWallpaperFocalPointInfo final { - bool operator==(const CreativeNewTabPageAdWallpaperFocalPointInfo&) const = - default; - - int x = 0; - int y = 0; -}; - -} // namespace brave_ads - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.cc b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.cc deleted file mode 100644 index 32cc2db27421..000000000000 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2020 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.h" - -namespace brave_ads { - -CreativeNewTabPageAdWallpaperInfo::CreativeNewTabPageAdWallpaperInfo() = - default; - -CreativeNewTabPageAdWallpaperInfo::CreativeNewTabPageAdWallpaperInfo( - const CreativeNewTabPageAdWallpaperInfo& other) = default; - -CreativeNewTabPageAdWallpaperInfo& CreativeNewTabPageAdWallpaperInfo::operator=( - const CreativeNewTabPageAdWallpaperInfo& other) = default; - -CreativeNewTabPageAdWallpaperInfo::CreativeNewTabPageAdWallpaperInfo( - CreativeNewTabPageAdWallpaperInfo&& other) noexcept = default; - -CreativeNewTabPageAdWallpaperInfo& CreativeNewTabPageAdWallpaperInfo::operator=( - CreativeNewTabPageAdWallpaperInfo&& other) noexcept = default; - -CreativeNewTabPageAdWallpaperInfo::~CreativeNewTabPageAdWallpaperInfo() = - default; - -} // namespace brave_ads diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.h b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.h deleted file mode 100644 index e95be43dbe1b..000000000000 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_info.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ - -#include - -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpaper_focal_point_info.h" -#include "brave/components/brave_ads/core/public/serving/targeting/condition_matcher/condition_matcher_util.h" -#include "url/gurl.h" - -namespace brave_ads { - -struct CreativeNewTabPageAdWallpaperInfo final { - CreativeNewTabPageAdWallpaperInfo(); - - CreativeNewTabPageAdWallpaperInfo(const CreativeNewTabPageAdWallpaperInfo&); - CreativeNewTabPageAdWallpaperInfo& operator=( - const CreativeNewTabPageAdWallpaperInfo&); - - CreativeNewTabPageAdWallpaperInfo( - CreativeNewTabPageAdWallpaperInfo&&) noexcept; - CreativeNewTabPageAdWallpaperInfo& operator=( - CreativeNewTabPageAdWallpaperInfo&&) noexcept; - - ~CreativeNewTabPageAdWallpaperInfo(); - - bool operator==(const CreativeNewTabPageAdWallpaperInfo&) const = default; - - GURL image_url; - CreativeNewTabPageAdWallpaperFocalPointInfo focal_point; - ConditionMatcherMap condition_matchers; -}; - -using CreativeNewTabPageAdWallpaperList = - std::vector; - -} // namespace brave_ads - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.cc b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.cc deleted file mode 100644 index debb4a3f4529..000000000000 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.cc +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h" - -#include -#include -#include -#include - -#include "base/base64.h" -#include "base/check.h" -#include "base/location.h" -#include "base/ranges/algorithm.h" -#include "base/strings/strcat.h" -#include "brave/components/brave_ads/core/internal/common/database/database_column_util.h" -#include "brave/components/brave_ads/core/internal/common/database/database_table_util.h" -#include "brave/components/brave_ads/core/internal/common/database/database_transaction_util.h" -#include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" - -namespace brave_ads::database::table { - -namespace { - -constexpr char kTableName[] = "creative_new_tab_page_ad_wallpapers"; - -std::string ConditionMatchersToString( - const ConditionMatcherMap& condition_matchers) { - std::vector condition_matchers_as_string; - condition_matchers_as_string.reserve(condition_matchers.size()); - - for (const auto& [pref_name, condition] : condition_matchers) { - // We base64 encode the `pref_name` and `condition` to avoid any issues with - // pref paths and conditions that contain either `|` or `;`. - - const std::string condition_matcher = base::StrCat( - {base::Base64Encode(pref_name), "|", base::Base64Encode(condition)}); - condition_matchers_as_string.push_back(condition_matcher); - } - - return base::JoinString(condition_matchers_as_string, ";"); -} - -size_t BindColumns(const mojom::DBActionInfoPtr& mojom_db_action, - const CreativeNewTabPageAdList& creative_ads) { - CHECK(mojom_db_action); - CHECK(!creative_ads.empty()); - - size_t row_count = 0; - - int index = 0; - for (const auto& creative_ad : creative_ads) { - for (const auto& wallpaper : creative_ad.wallpapers) { - BindColumnString(mojom_db_action, index++, - creative_ad.creative_instance_id); - BindColumnString(mojom_db_action, index++, wallpaper.image_url.spec()); - BindColumnInt(mojom_db_action, index++, wallpaper.focal_point.x); - BindColumnInt(mojom_db_action, index++, wallpaper.focal_point.y); - BindColumnString(mojom_db_action, index++, - ConditionMatchersToString(wallpaper.condition_matchers)); - } - - row_count += creative_ad.wallpapers.size(); - } - - return row_count; -} - -} // namespace - -void CreativeNewTabPageAdWallpapers::Insert( - const mojom::DBTransactionInfoPtr& mojom_db_transaction, - const CreativeNewTabPageAdList& creative_ads) { - CHECK(mojom_db_transaction); - - CreativeNewTabPageAdList filtered_creative_ads; - base::ranges::copy_if(creative_ads, std::back_inserter(filtered_creative_ads), - [](const CreativeNewTabPageAdInfo& creative_ad) { - return !creative_ad.wallpapers.empty(); - }); - - if (filtered_creative_ads.empty()) { - return; - } - - mojom::DBActionInfoPtr mojom_db_action = mojom::DBActionInfo::New(); - mojom_db_action->type = mojom::DBActionInfo::Type::kExecuteWithBindings; - mojom_db_action->sql = BuildInsertSql(mojom_db_action, filtered_creative_ads); - mojom_db_transaction->actions.push_back(std::move(mojom_db_action)); -} - -void CreativeNewTabPageAdWallpapers::Delete(ResultCallback callback) const { - mojom::DBTransactionInfoPtr mojom_db_transaction = - mojom::DBTransactionInfo::New(); - - DeleteTable(mojom_db_transaction, GetTableName()); - - RunDBTransaction(FROM_HERE, std::move(mojom_db_transaction), - std::move(callback)); -} - -std::string CreativeNewTabPageAdWallpapers::GetTableName() const { - return kTableName; -} - -void CreativeNewTabPageAdWallpapers::Create( - const mojom::DBTransactionInfoPtr& mojom_db_transaction) { - CHECK(mojom_db_transaction); - - Execute(mojom_db_transaction, R"( - CREATE TABLE creative_new_tab_page_ad_wallpapers ( - creative_instance_id TEXT NOT NULL, - image_url TEXT NOT NULL, - focal_point_x INT NOT NULL, - focal_point_y INT NOT NULL, - condition_matchers TEXT NOT NULL, - PRIMARY KEY ( - creative_instance_id, - image_url, - focal_point_x, - focal_point_y, - condition_matchers - ) ON CONFLICT REPLACE - );)"); -} - -void CreativeNewTabPageAdWallpapers::Migrate( - const mojom::DBTransactionInfoPtr& mojom_db_transaction, - int to_version) { - CHECK(mojom_db_transaction); - - switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); - break; - } - } -} - -/////////////////////////////////////////////////////////////////////////////// - -void CreativeNewTabPageAdWallpapers::MigrateToV45( - const mojom::DBTransactionInfoPtr& mojom_db_transaction) { - CHECK(mojom_db_transaction); - - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. - DropTable(mojom_db_transaction, GetTableName()); - Create(mojom_db_transaction); -} - -std::string CreativeNewTabPageAdWallpapers::BuildInsertSql( - const mojom::DBActionInfoPtr& mojom_db_action, - const CreativeNewTabPageAdList& creative_ads) const { - CHECK(mojom_db_action); - CHECK(!creative_ads.empty()); - - const size_t row_count = BindColumns(mojom_db_action, creative_ads); - - return base::ReplaceStringPlaceholders( - R"( - INSERT INTO $1 ( - creative_instance_id, - image_url, - focal_point_x, - focal_point_y, - condition_matchers - ) VALUES $2;)", - {GetTableName(), - BuildBindColumnPlaceholders(/*column_count=*/5, row_count)}, - nullptr); -} - -} // namespace brave_ads::database::table diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h deleted file mode 100644 index 9f4f1adc739d..000000000000 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPERS_DATABASE_TABLE_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPERS_DATABASE_TABLE_H_ - -#include - -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h" -#include "brave/components/brave_ads/core/internal/database/database_table_interface.h" -#include "brave/components/brave_ads/core/mojom/brave_ads.mojom-forward.h" -#include "brave/components/brave_ads/core/public/ads_client/ads_client_callback.h" - -namespace brave_ads::database::table { - -class CreativeNewTabPageAdWallpapers final : public TableInterface { - public: - void Insert(const mojom::DBTransactionInfoPtr& mojom_db_transaction, - const CreativeNewTabPageAdList& creative_ads); - - void Delete(ResultCallback callback) const; - - std::string GetTableName() const override; - - void Create(const mojom::DBTransactionInfoPtr& mojom_db_transaction) override; - void Migrate(const mojom::DBTransactionInfoPtr& mojom_db_transaction, - int to_version) override; - - private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); - - std::string BuildInsertSql( - const mojom::DBActionInfoPtr& mojom_db_action, - const CreativeNewTabPageAdList& creative_ads) const; -}; - -} // namespace brave_ads::database::table - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_AD_WALLPAPERS_DATABASE_TABLE_H_ diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table_unittest.cc b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table_unittest.cc deleted file mode 100644 index 16f854994d9e..000000000000 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table_unittest.cc +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h" - -#include "testing/gtest/include/gtest/gtest.h" - -// npm run test -- brave_unit_tests --filter=BraveAds* - -namespace brave_ads::database::table { - -TEST(BraveAdsCreativeNewTabPageAdWallpapersDatabaseTableTest, GetTableName) { - // Arrange - const CreativeNewTabPageAdWallpapers database_table; - - // Act & Assert - EXPECT_EQ("creative_new_tab_page_ad_wallpapers", - database_table.GetTableName()); -} - -} // namespace brave_ads::database::table diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.cc b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.cc index dfc0c507609b..c9a3868807df 100644 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.cc +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.cc @@ -9,12 +9,10 @@ #include #include -#include "base/base64.h" #include "base/containers/contains.h" #include "base/functional/bind.h" #include "base/location.h" #include "base/strings/strcat.h" -#include "base/strings/string_split.h" #include "base/time/time.h" #include "brave/components/brave_ads/core/internal/common/containers/container_util.h" #include "brave/components/brave_ads/core/internal/common/database/database_column_util.h" @@ -24,6 +22,7 @@ #include "brave/components/brave_ads/core/internal/common/logging_util.h" #include "brave/components/brave_ads/core/internal/common/time/time_util.h" #include "brave/components/brave_ads/core/internal/creatives/creative_ad_info.h" +#include "brave/components/brave_ads/core/internal/creatives/creative_ads_database_table_util.h" #include "brave/components/brave_ads/core/internal/segments/segment_util.h" #include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" #include "brave/components/brave_ads/core/public/serving/targeting/condition_matcher/condition_matcher_util.h" @@ -40,39 +39,6 @@ constexpr char kTableName[] = "creative_new_tab_page_ads"; constexpr int kDefaultBatchSize = 50; -ConditionMatcherMap StringToConditionMatchers(const std::string& value) { - const std::vector condition_matchers_as_string = - base::SplitString(value, ";", base::TRIM_WHITESPACE, - base::SPLIT_WANT_NONEMPTY); - - ConditionMatcherMap condition_matchers; - for (const auto& condition_matcher_as_string : condition_matchers_as_string) { - const std::vector condition_matcher = - base::SplitString(condition_matcher_as_string, "|", - base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - if (condition_matcher.size() != 2) { - // Malfomed condition matcher. - continue; - } - - std::string pref_path; - if (!base::Base64Decode(condition_matcher[0], &pref_path)) { - // Malfomed condition matcher. - continue; - } - - std::string condition; - if (!base::Base64Decode(condition_matcher[1], &condition)) { - // Malfomed condition matcher. - continue; - } - - condition_matchers.emplace(pref_path, condition); - } - - return condition_matchers; -} - void BindColumnTypes(const mojom::DBActionInfoPtr& mojom_db_action) { CHECK(mojom_db_action); @@ -91,24 +57,16 @@ void BindColumnTypes(const mojom::DBActionInfoPtr& mojom_db_action) { mojom::DBBindColumnType::kInt, // total_max mojom::DBBindColumnType::kDouble, // value mojom::DBBindColumnType::kString, // split_test_group + mojom::DBBindColumnType::kString, // condition_matchers mojom::DBBindColumnType::kString, // segment mojom::DBBindColumnType::kString, // geo_target mojom::DBBindColumnType::kString, // target_url mojom::DBBindColumnType::kString, // company_name - mojom::DBBindColumnType::kString, // image_url mojom::DBBindColumnType::kString, // alt mojom::DBBindColumnType::kDouble, // ptr mojom::DBBindColumnType::kString, // dayparts->days_of_week mojom::DBBindColumnType::kInt, // dayparts->start_minute - mojom::DBBindColumnType::kInt, // dayparts->end_minute - mojom::DBBindColumnType:: - kString, // creative_new_tab_page_ad_wallpapers->image_url - mojom::DBBindColumnType:: - kInt, // creative_new_tab_page_ad_wallpapers->focal_point->x - mojom::DBBindColumnType:: - kInt, // creative_new_tab_page_ad_wallpapers->focal_point->y - mojom::DBBindColumnType:: - kString // creative_new_tab_page_ad_wallpapers->condition_matchers + mojom::DBBindColumnType::kInt // dayparts->end_minute }; } @@ -126,7 +84,6 @@ size_t BindColumns(const mojom::DBActionInfoPtr& mojom_db_action, BindColumnString(mojom_db_action, index++, creative_ad.creative_set_id); BindColumnString(mojom_db_action, index++, creative_ad.campaign_id); BindColumnString(mojom_db_action, index++, creative_ad.company_name); - BindColumnString(mojom_db_action, index++, creative_ad.image_url.spec()); BindColumnString(mojom_db_action, index++, creative_ad.alt); ++row_count; @@ -154,11 +111,12 @@ CreativeNewTabPageAdInfo FromMojomRow(const mojom::DBRowInfoPtr& mojom_db_row) { creative_ad.total_max = ColumnInt(mojom_db_row, 11); creative_ad.value = ColumnDouble(mojom_db_row, 12); creative_ad.split_test_group = ColumnString(mojom_db_row, 13); - creative_ad.segment = ColumnString(mojom_db_row, 14); - creative_ad.geo_targets.insert(ColumnString(mojom_db_row, 15)); - creative_ad.target_url = GURL(ColumnString(mojom_db_row, 16)); - creative_ad.company_name = ColumnString(mojom_db_row, 17); - creative_ad.image_url = GURL(ColumnString(mojom_db_row, 18)); + creative_ad.condition_matchers = + StringToConditionMatchers(ColumnString(mojom_db_row, 14)); + creative_ad.segment = ColumnString(mojom_db_row, 15); + creative_ad.geo_targets.insert(ColumnString(mojom_db_row, 16)); + creative_ad.target_url = GURL(ColumnString(mojom_db_row, 17)); + creative_ad.company_name = ColumnString(mojom_db_row, 18); creative_ad.alt = ColumnString(mojom_db_row, 19); creative_ad.pass_through_rate = ColumnDouble(mojom_db_row, 20); @@ -168,14 +126,6 @@ CreativeNewTabPageAdInfo FromMojomRow(const mojom::DBRowInfoPtr& mojom_db_row) { daypart.end_minute = ColumnInt(mojom_db_row, 23); creative_ad.dayparts.push_back(daypart); - CreativeNewTabPageAdWallpaperInfo wallpaper; - wallpaper.image_url = GURL(ColumnString(mojom_db_row, 24)); - wallpaper.focal_point.x = ColumnInt(mojom_db_row, 25); - wallpaper.focal_point.y = ColumnInt(mojom_db_row, 26); - wallpaper.condition_matchers = - StringToConditionMatchers(ColumnString(mojom_db_row, 27)); - creative_ad.wallpapers.push_back(wallpaper); - return creative_ad; } @@ -209,12 +159,6 @@ CreativeNewTabPageAdList GetCreativeAdsFromResponse( iter->second.dayparts.push_back(daypart); } } - - for (const auto& wallpaper : creative_ad.wallpapers) { - if (!base::Contains(iter->second.wallpapers, wallpaper)) { - iter->second.wallpapers.push_back(wallpaper); - } - } } CreativeNewTabPageAdList normalized_creative_ads; @@ -291,30 +235,88 @@ CreativeNewTabPageAds::~CreativeNewTabPageAds() = default; void CreativeNewTabPageAds::Save(const CreativeNewTabPageAdList& creative_ads, ResultCallback callback) { - if (creative_ads.empty()) { - return std::move(callback).Run(/*success=*/true); - } - mojom::DBTransactionInfoPtr mojom_db_transaction = mojom::DBTransactionInfo::New(); - const std::vector batches = - SplitVector(creative_ads, batch_size_); - - for (const auto& batch : batches) { - Insert(mojom_db_transaction, batch); - - const CreativeAdList creative_ads_batch(batch.cbegin(), batch.cend()); - campaigns_database_table_.Insert(mojom_db_transaction, creative_ads_batch); - creative_ads_database_table_.Insert(mojom_db_transaction, - creative_ads_batch); - creative_new_tab_page_ad_wallpapers_database_table_.Insert( - mojom_db_transaction, batch); - dayparts_database_table_.Insert(mojom_db_transaction, creative_ads_batch); - deposits_database_table_.Insert(mojom_db_transaction, creative_ads_batch); - geo_targets_database_table_.Insert(mojom_db_transaction, + // Replace existing creative new tab page ads. + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + campaigns + WHERE + id IN ( + SELECT + DISTINCT campaign_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + geo_targets + WHERE + campaign_id IN ( + SELECT + DISTINCT campaign_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + dayparts + WHERE + campaign_id IN ( + SELECT + DISTINCT campaign_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + segments + WHERE + creative_set_id IN ( + SELECT + DISTINCT creative_set_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + creative_ads + WHERE + creative_instance_id IN ( + SELECT + DISTINCT creative_instance_id + FROM + creative_new_tab_page_ads + );)"); + + database::Execute(mojom_db_transaction, R"( + DELETE FROM + creative_new_tab_page_ads;)"); + + if (!creative_ads.empty()) { + const std::vector batches = + SplitVector(creative_ads, batch_size_); + + for (const auto& batch : batches) { + Insert(mojom_db_transaction, batch); + + const CreativeAdList creative_ads_batch(batch.cbegin(), batch.cend()); + campaigns_database_table_.Insert(mojom_db_transaction, creative_ads_batch); - segments_database_table_.Insert(mojom_db_transaction, creative_ads_batch); + creative_ads_database_table_.Insert(mojom_db_transaction, + creative_ads_batch); + dayparts_database_table_.Insert(mojom_db_transaction, creative_ads_batch); + deposits_database_table_.Insert(mojom_db_transaction, creative_ads_batch); + geo_targets_database_table_.Insert(mojom_db_transaction, + creative_ads_batch); + segments_database_table_.Insert(mojom_db_transaction, creative_ads_batch); + } } RunDBTransaction(FROM_HERE, std::move(mojom_db_transaction), @@ -360,25 +362,20 @@ void CreativeNewTabPageAds::GetForCreativeInstanceId( creative_ads.total_max, creative_ads.value, creative_ads.split_test_group, + creative_ads.condition_matchers, segments.segment, geo_targets.geo_target, creative_ads.target_url, creative_new_tab_page_ad.company_name, - creative_new_tab_page_ad.image_url, creative_new_tab_page_ad.alt, campaigns.ptr, dayparts.days_of_week, dayparts.start_minute, - dayparts.end_minute, - creative_new_tab_page_ad_wallpapers.image_url, - creative_new_tab_page_ad_wallpapers.focal_point_x, - creative_new_tab_page_ad_wallpapers.focal_point_y, - creative_new_tab_page_ad_wallpapers.condition_matchers + dayparts.end_minute FROM $1 AS creative_new_tab_page_ad INNER JOIN campaigns ON campaigns.id = creative_new_tab_page_ad.campaign_id INNER JOIN creative_ads ON creative_ads.creative_instance_id = creative_new_tab_page_ad.creative_instance_id - INNER JOIN creative_new_tab_page_ad_wallpapers ON creative_new_tab_page_ad_wallpapers.creative_instance_id = creative_new_tab_page_ad.creative_instance_id INNER JOIN dayparts ON dayparts.campaign_id = creative_new_tab_page_ad.campaign_id INNER JOIN geo_targets ON geo_targets.campaign_id = creative_new_tab_page_ad.campaign_id INNER JOIN segments ON segments.creative_set_id = creative_new_tab_page_ad.creative_set_id @@ -422,25 +419,20 @@ void CreativeNewTabPageAds::GetForSegments( creative_ads.total_max, creative_ads.value, creative_ads.split_test_group, + creative_ads.condition_matchers, segments.segment, geo_targets.geo_target, creative_ads.target_url, creative_new_tab_page_ad.company_name, - creative_new_tab_page_ad.image_url, creative_new_tab_page_ad.alt, campaigns.ptr, dayparts.days_of_week, dayparts.start_minute, - dayparts.end_minute, - creative_new_tab_page_ad_wallpapers.image_url, - creative_new_tab_page_ad_wallpapers.focal_point_x, - creative_new_tab_page_ad_wallpapers.focal_point_y, - creative_new_tab_page_ad_wallpapers.condition_matchers + dayparts.end_minute FROM $1 AS creative_new_tab_page_ad INNER JOIN campaigns ON campaigns.id = creative_new_tab_page_ad.campaign_id INNER JOIN creative_ads ON creative_ads.creative_instance_id = creative_new_tab_page_ad.creative_instance_id - INNER JOIN creative_new_tab_page_ad_wallpapers ON creative_new_tab_page_ad_wallpapers.creative_instance_id = creative_new_tab_page_ad.creative_instance_id INNER JOIN dayparts ON dayparts.campaign_id = creative_new_tab_page_ad.campaign_id INNER JOIN geo_targets ON geo_targets.campaign_id = creative_new_tab_page_ad.campaign_id INNER JOIN segments ON segments.creative_set_id = creative_new_tab_page_ad.creative_set_id @@ -488,25 +480,20 @@ void CreativeNewTabPageAds::GetForActiveCampaigns( creative_ads.total_max, creative_ads.value, creative_ads.split_test_group, + creative_ads.condition_matchers, segments.segment, geo_targets.geo_target, creative_ads.target_url, creative_new_tab_page_ad.company_name, - creative_new_tab_page_ad.image_url, creative_new_tab_page_ad.alt, campaigns.ptr, dayparts.days_of_week, dayparts.start_minute, - dayparts.end_minute, - creative_new_tab_page_ad_wallpapers.image_url, - creative_new_tab_page_ad_wallpapers.focal_point_x, - creative_new_tab_page_ad_wallpapers.focal_point_y, - creative_new_tab_page_ad_wallpapers.condition_matchers + dayparts.end_minute FROM $1 AS creative_new_tab_page_ad INNER JOIN campaigns ON campaigns.id = creative_new_tab_page_ad.campaign_id INNER JOIN creative_ads ON creative_ads.creative_instance_id = creative_new_tab_page_ad.creative_instance_id - INNER JOIN creative_new_tab_page_ad_wallpapers ON creative_new_tab_page_ad_wallpapers.creative_instance_id = creative_new_tab_page_ad.creative_instance_id INNER JOIN dayparts ON dayparts.campaign_id = creative_new_tab_page_ad.campaign_id INNER JOIN geo_targets ON geo_targets.campaign_id = creative_new_tab_page_ad.campaign_id INNER JOIN segments ON segments.creative_set_id = creative_new_tab_page_ad.creative_set_id @@ -534,7 +521,6 @@ void CreativeNewTabPageAds::Create( creative_set_id TEXT NOT NULL, campaign_id TEXT NOT NULL, company_name TEXT NOT NULL, - image_url TEXT NOT NULL, alt TEXT NOT NULL );)"); } @@ -545,8 +531,8 @@ void CreativeNewTabPageAds::Migrate( CHECK(mojom_db_transaction); switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -554,12 +540,17 @@ void CreativeNewTabPageAds::Migrate( /////////////////////////////////////////////////////////////////////////////// -void CreativeNewTabPageAds::MigrateToV45( +void CreativeNewTabPageAds::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // Wallpapers table has been deprecated. + DropTable(mojom_db_transaction, "creative_new_tab_page_ad_wallpapers"); + + // Recreating the table is safe because it will be repopulated after + // downloading the component resource. However, after this migration, we + // should not drop the table as it must align with the metadata in the + // component resource `campaigns.json`. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } @@ -594,11 +585,10 @@ std::string CreativeNewTabPageAds::BuildInsertSql( creative_set_id, campaign_id, company_name, - image_url, alt ) VALUES $2;)", {GetTableName(), - BuildBindColumnPlaceholders(/*column_count=*/6, row_count)}, + BuildBindColumnPlaceholders(/*column_count=*/5, row_count)}, nullptr); } diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.h b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.h index 6039d4f7aa6c..f6befdb6f395 100644 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.h +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.h @@ -17,7 +17,6 @@ #include "brave/components/brave_ads/core/internal/creatives/dayparts_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/geo_targets_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/segments_database_table.h" #include "brave/components/brave_ads/core/internal/database/database_table_interface.h" #include "brave/components/brave_ads/core/internal/segments/segment_alias.h" @@ -71,7 +70,7 @@ class CreativeNewTabPageAds final : public TableInterface { int to_version) override; private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); void Insert(const mojom::DBTransactionInfoPtr& mojom_db_transaction, const CreativeNewTabPageAdList& creative_ads); @@ -84,8 +83,6 @@ class CreativeNewTabPageAds final : public TableInterface { Campaigns campaigns_database_table_; CreativeAds creative_ads_database_table_; - CreativeNewTabPageAdWallpapers - creative_new_tab_page_ad_wallpapers_database_table_; Dayparts dayparts_database_table_; Deposits deposits_database_table_; GeoTargets geo_targets_database_table_; diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.cc b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.cc index 7061e0d90187..6ec4c3c2a270 100644 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.cc +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.cc @@ -5,30 +5,81 @@ #include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.h" +#include + +#include "base/containers/flat_set.h" #include "base/functional/bind.h" +#include "base/json/json_reader.h" +#include "base/strings/string_number_conversions.h" +#include "base/values.h" #include "brave/components/brave_ads/core/internal/common/logging_util.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h" +#include "brave/components/brave_ads/core/internal/creatives/conversions/creative_set_conversion_database_table_util.h" +#include "brave/components/brave_ads/core/internal/creatives/conversions/creative_set_conversion_info.h" +#include "brave/components/brave_ads/core/internal/creatives/creative_daypart_info.h" +#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h" #include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.h" +#include "brave/components/brave_ads/core/internal/segments/segment_alias.h" +#include "brave/components/brave_ads/core/internal/segments/segment_constants.h" +#include "url/gurl.h" namespace brave_ads::database { -void DeleteCreativeNewTabPageAds() { - const table::CreativeNewTabPageAds database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete creative new tab page ads"); - } - })); -} +namespace { -void DeleteCreativeNewTabPageAdWallpapers() { - const table::CreativeNewTabPageAdWallpapers database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete creative new tab page ad wallpapers"); - } - })); -} +// Campaign keys. +constexpr char kCampaignsKey[] = "campaigns"; +constexpr char kCampaignIdKey[] = "campaignId"; + +constexpr char kCampaignAdvertiserIdKey[] = "advertiserId"; + +constexpr char kCampaignStartAtKey[] = "startAt"; +constexpr char kCampaignEndAtKey[] = "endAt"; + +constexpr char kCampaignDailyCapKey[] = "dailyCap"; + +constexpr char kCampaignPriorityKey[] = "priority"; +constexpr char kCampaignPassThroughRateKey[] = "ptr"; + +constexpr char kCampaignGeoTargetsKey[] = "geoTargets"; + +constexpr char kCampaignDayPartsKey[] = "dayParts"; +constexpr char kCampaignDayPartDaysOfWeekKey[] = "daysOfWeek"; +constexpr char kCampaignDayPartStartMinuteKey[] = "startMinute"; +constexpr char kCampaignDayPartEndMinuteKey[] = "endMinute"; + +// Creative set keys. +constexpr char kCreativeSetsKey[] = "creativeSets"; +constexpr char kCreativeSetIdKey[] = "creativeSetId"; + +constexpr char kCreativeSetPerDayKey[] = "perDay"; +constexpr char kCreativeSetPerWeekKey[] = "perWeek"; +constexpr char kCreativeSetPerMonthKey[] = "perMonth"; +constexpr char kCreativeSetTotalMaxKey[] = "totalMax"; + +constexpr char kCreativeSetValueKey[] = "value"; + +constexpr char kCreativeSetSegmentsKey[] = "segments"; + +constexpr char kCreativeSetSplitTestGroupKey[] = "splitTestGroup"; + +constexpr char kCreativeSetConversionsKey[] = "conversions"; +constexpr char kCreativeSetConversionUrlPatternKey[] = "urlPattern"; +constexpr char kCreativeSetConversionObservationWindowKey[] = + "observationWindow"; +constexpr char kCreativeSetConversionPublicKeyKey[] = "publicKey"; + +// Creative keys. +constexpr char kCreativesKey[] = "creatives"; +constexpr char kCreativeInstanceIdKey[] = "creativeInstanceId"; + +constexpr char kCreativeCompanyNameKey[] = "companyName"; +constexpr char kCreativeAltKey[] = "alt"; + +constexpr char kCreativeTargetUrlKey[] = "targetUrl"; + +constexpr char kCreativeConditionMatchersKey[] = "conditionMatchers"; +constexpr char kCreativeConditionMatcherConditionKey[] = "condition"; +constexpr char kCreativeConditionMatcherPrefPathKey[] = "prefPath"; void SaveCreativeNewTabPageAds(const CreativeNewTabPageAdList& creative_ads) { table::CreativeNewTabPageAds database_table; @@ -42,4 +93,377 @@ void SaveCreativeNewTabPageAds(const CreativeNewTabPageAdList& creative_ads) { })); } +} // namespace + +// This temporary implementation has high congitive complexity to parse and +// save creative new tab page ads. It will be replaced when new tab page ads are +// served from the ads component. +bool ParseAndSaveCreativeNewTabPageAds(const std::string& json) { + const std::optional dict = + base::JSONReader::ReadDict(json); + if (!dict) { + BLOG(0, "Failed to parse creative new tab page ads"); + return false; + } + + const base::Value::List* const campaign_list = dict->FindList(kCampaignsKey); + if (!campaign_list) { + BLOG(0, "Campaigns are required"); + return false; + } + + CreativeNewTabPageAdList creative_ads; + CreativeSetConversionList creative_set_conversions; + + // Campaigns. + for (const auto& campaign_value : *campaign_list) { + CreativeNewTabPageAdInfo creative_ad; + + const base::Value::Dict* const campaign_dict = campaign_value.GetIfDict(); + if (!campaign_dict) { + BLOG(0, "Invalid campaign, skipping campaign"); + continue; + } + + const std::string* const campaign_id = + campaign_dict->FindString(kCampaignIdKey); + if (!campaign_id) { + BLOG(0, "Campaign ID is required, skipping campaign"); + continue; + } + creative_ad.campaign_id = *campaign_id; + + const std::string* const advertiser_id = + campaign_dict->FindString(kCampaignAdvertiserIdKey); + if (!advertiser_id) { + // Advertiser ID is required. + BLOG(0, "Advertiser ID is required, skipping campaign"); + continue; + } + creative_ad.advertiser_id = *advertiser_id; + + if (const std::string* const start_at = + campaign_dict->FindString(kCampaignStartAtKey)) { + // Start at is optional. + if (!base::Time::FromUTCString(start_at->c_str(), + &creative_ad.start_at)) { + BLOG(0, "Failed to parse campaign start at, skipping campaign"); + continue; + } + } else { + // Default to starting immediately. + creative_ad.start_at = base::Time::Now(); + } + + if (const std::string* const end_at = + campaign_dict->FindString(kCampaignEndAtKey)) { + // End at is optional. + if (!base::Time::FromUTCString(end_at->c_str(), &creative_ad.end_at)) { + BLOG(0, "Failed to parse campaign end at, skipping campaign"); + continue; + } + } else { + // Default to running indefinitely. + creative_ad.end_at = base::Time::Max(); + } + + creative_ad.daily_cap = + campaign_dict->FindInt(kCampaignDailyCapKey).value_or(0); + + creative_ad.priority = + campaign_dict->FindInt(kCampaignPriorityKey).value_or(0); + + creative_ad.pass_through_rate = + campaign_dict->FindInt(kCampaignPassThroughRateKey).value_or(1.0); + + // Geo targets. + const base::Value::List* const geo_target_list = + campaign_dict->FindList(kCampaignGeoTargetsKey); + if (!geo_target_list || geo_target_list->empty()) { + // Geo targets are required. + BLOG(0, "Geo targets are required, skipping campaign"); + continue; + } + + base::flat_set geo_targets; + for (const auto& geo_target_value : *geo_target_list) { + const std::string* const geo_target = geo_target_value.GetIfString(); + if (!geo_target) { + BLOG(0, "Invalid geo target, skipping geo target"); + continue; + } + + geo_targets.insert(*geo_target); + } + creative_ad.geo_targets = geo_targets; + + // Dayparts. + CreativeDaypartList dayparts; + if (const base::Value::List* const daypart_list = + campaign_dict->FindList(kCampaignDayPartsKey)) { + // Dayparts are optional. + for (const auto& daypart_value : *daypart_list) { + const base::Value::Dict* const daypart_dict = daypart_value.GetIfDict(); + if (!daypart_dict) { + BLOG(0, "Invalid daypart, skipping campaign"); + continue; + } + + const std::string* const days_of_week = + daypart_dict->FindString(kCampaignDayPartDaysOfWeekKey); + if (!days_of_week) { + // Days of week is required. + BLOG(0, "Days of week is required, skipping campaign"); + continue; + } + + const int start_minute = + daypart_dict->FindInt(kCampaignDayPartStartMinuteKey) + .value_or(0 /*00:00*/); + + const int end_minute = + daypart_dict->FindInt(kCampaignDayPartEndMinuteKey) + .value_or( + (base::Days(1) - base::Minutes(1)).InMinutes() /*23:59*/); + + dayparts.push_back( + CreativeDaypartInfo{*days_of_week, start_minute, end_minute}); + } + } + if (dayparts.empty()) { + // Default to all day every day. + CreativeDaypartInfo daypart; + dayparts.push_back(daypart); + } + creative_ad.dayparts = dayparts; + + // Creative sets. + const base::Value::List* const creative_set_list = + campaign_dict->FindList(kCreativeSetsKey); + if (!creative_set_list) { + // Creative sets are required. + BLOG(0, "Creative sets are required, skipping campaign"); + continue; + } + + for (const auto& creative_set_value : *creative_set_list) { + const base::Value::Dict* const creative_set_dict = + creative_set_value.GetIfDict(); + if (!creative_set_dict) { + BLOG(0, "Invalid creative set, skipping creative set"); + continue; + } + + // Creative set. + const std::string* const creative_set_id = + creative_set_dict->FindString(kCreativeSetIdKey); + if (!creative_set_id) { + // Creative set ID is required. + BLOG(0, "Creative set ID is required, skipping creative set"); + continue; + } + creative_ad.creative_set_id = *creative_set_id; + + creative_ad.per_day = + creative_set_dict->FindInt(kCreativeSetPerDayKey).value_or(0); + creative_ad.per_week = + creative_set_dict->FindInt(kCreativeSetPerWeekKey).value_or(0); + creative_ad.per_month = + creative_set_dict->FindInt(kCreativeSetPerMonthKey).value_or(0); + creative_ad.total_max = + creative_set_dict->FindInt(kCreativeSetTotalMaxKey).value_or(0); + + if (const std::string* const associated_value = + creative_set_dict->FindString(kCreativeSetValueKey)) { + // Value is optional. + if (!base::StringToDouble(*associated_value, &creative_ad.value)) { + BLOG(0, "Failed to parse associated value, skipping creative set"); + continue; + } + } else { + // Default to zero value. + creative_ad.value = 0.0; + } + + // Split test group. + if (const std::string* const split_test_group_value = + creative_set_dict->FindString(kCreativeSetSplitTestGroupKey)) { + // Split test group is optional. + creative_ad.split_test_group = *split_test_group_value; + } + + // Conversions. + const base::Value::List* const conversion_list = + creative_set_dict->FindList(kCreativeSetConversionsKey); + if (conversion_list) { + // Conversions are optional. + for (const auto& conversion_value : *conversion_list) { + const base::Value::Dict* const conversion_dict = + conversion_value.GetIfDict(); + if (!conversion_dict) { + BLOG(0, "Invalid conversion, skipping conversion"); + continue; + } + + CreativeSetConversionInfo creative_set_conversion; + + creative_set_conversion.id = creative_ad.creative_set_id; + + const std::string* const url_pattern = + conversion_dict->FindString(kCreativeSetConversionUrlPatternKey); + if (!url_pattern) { + // URL pattern is required. + BLOG(0, + "URL pattern is required, skipping creative set conversion"); + continue; + } + creative_set_conversion.url_pattern = *url_pattern; + + const int observation_window = + conversion_dict + ->FindInt(kCreativeSetConversionObservationWindowKey) + .value_or(7); + creative_set_conversion.observation_window = + base::Days(observation_window); + + creative_set_conversion.expire_at = + creative_ad.end_at + creative_set_conversion.observation_window; + + const std::string* const public_key = + conversion_dict->FindString(kCreativeSetConversionPublicKeyKey); + if (public_key) { + creative_set_conversion.verifiable_advertiser_public_key_base64 = + *public_key; + } + + creative_set_conversions.push_back(creative_set_conversion); + } + } + + // Segments. + SegmentList segments; + if (const base::Value::List* const segment_list = + creative_set_dict->FindList(kCreativeSetSegmentsKey)) { + // Segments are optional. + for (const auto& segment_value : *segment_list) { + const std::string* const segment = segment_value.GetIfString(); + if (!segment) { + BLOG(0, "Invalid segment, skipping segment"); + continue; + } + + segments.push_back(*segment); + } + } + if (segments.empty()) { + // Default to untargeted segment. + segments.emplace_back(kUntargetedSegment); + } + + // Creatives. + const base::Value::List* const creative_list = + creative_set_dict->FindList(kCreativesKey); + if (!creative_list) { + // Creatives are required. + BLOG(0, "Creatives are required, skipping creative set"); + continue; + } + + for (const auto& creative_value : *creative_list) { + const base::Value::Dict* const creative_dict = + creative_value.GetIfDict(); + if (!creative_dict) { + BLOG(0, "Invalid creative, skipping creative"); + continue; + } + + // Creative. + const std::string* const creative_instance_id = + creative_dict->FindString(kCreativeInstanceIdKey); + if (!creative_instance_id) { + // Creative instance ID is required. + BLOG(0, "Creative instance ID is required, skipping creative"); + continue; + } + creative_ad.creative_instance_id = *creative_instance_id; + + const std::string* const company_name = + creative_dict->FindString(kCreativeCompanyNameKey); + if (!company_name) { + // Company name is required. + BLOG(0, "Company name is required, skipping creative"); + continue; + } + creative_ad.company_name = *company_name; + + const std::string* const alt = + creative_dict->FindString(kCreativeAltKey); + if (!alt) { + // Alt is required. + BLOG(0, "Alt is required, skipping creative"); + continue; + } + creative_ad.alt = *alt; + + const std::string* const target_url = + creative_dict->FindString(kCreativeTargetUrlKey); + if (!target_url) { + // Target URL is required. + BLOG(0, "Target URL is required, skipping creative"); + continue; + } + creative_ad.target_url = GURL(*target_url); + + // Condition matchers. + const base::Value::List* const condition_matcher_list = + creative_dict->FindList(kCreativeConditionMatchersKey); + if (condition_matcher_list) { + // Condition matchers are optional. + for (const auto& condition_matcher_value : *condition_matcher_list) { + const base::Value::Dict* const condition_matcher_dict = + condition_matcher_value.GetIfDict(); + if (!condition_matcher_dict) { + BLOG(0, "Invalid condition matcher, skipping condition matcher"); + continue; + } + + const std::string* const condition = + condition_matcher_dict->FindString( + kCreativeConditionMatcherConditionKey); + if (!condition) { + // Condition is required. + BLOG(0, "Condition is required, skipping condition matcher"); + continue; + } + + const std::string* const pref_path = + condition_matcher_dict->FindString( + kCreativeConditionMatcherPrefPathKey); + if (!pref_path) { + // Pref path is required. + BLOG(0, "Pref path is required, skipping condition matcher"); + continue; + } + + creative_ad.condition_matchers.emplace(*pref_path, *condition); + } + } + + for (const auto& segment : segments) { + creative_ad.segment = segment; + creative_ads.push_back(creative_ad); + } + } + } + } + + SaveCreativeNewTabPageAds(creative_ads); + SaveCreativeSetConversions(creative_set_conversions); + + // It is assumed that the creative new tab page ads were saved successfully. + // Once we transition to serving new tab page ads from the ads component for + // both non-Rewards and Rewards, we can implement better validation. + return true; +} + } // namespace brave_ads::database diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.h b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.h index 628936ee0373..ba255f320702 100644 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.h +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.h @@ -6,14 +6,11 @@ #ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_ADS_DATABASE_UTIL_H_ #define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_NEW_TAB_PAGE_ADS_CREATIVE_NEW_TAB_PAGE_ADS_DATABASE_UTIL_H_ -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_info.h" +#include namespace brave_ads::database { -void DeleteCreativeNewTabPageAds(); -void DeleteCreativeNewTabPageAdWallpapers(); - -void SaveCreativeNewTabPageAds(const CreativeNewTabPageAdList& creative_ads); +bool ParseAndSaveCreativeNewTabPageAds(const std::string& json); } // namespace brave_ads::database diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util_unittest.cc b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util_unittest.cc new file mode 100644 index 000000000000..bde8a4dd66bb --- /dev/null +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util_unittest.cc @@ -0,0 +1,30 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util.h" + +#include "brave/components/brave_ads/core/internal/common/test/test_base.h" + +// npm run test -- brave_unit_tests --filter=BraveAds* + +namespace brave_ads { + +class BraveAdsCreativeNewTabPageAdsDatabaseUtilTest : public test::TestBase {}; + +TEST_F(BraveAdsCreativeNewTabPageAdsDatabaseUtilTest, ParseAndSaveCreativeAds) { + FAIL(); +} + +TEST_F(BraveAdsCreativeNewTabPageAdsDatabaseUtilTest, + DoNotParseAndSaveCreativeAdsWithMalformedJson) { + FAIL(); +} + +TEST_F(BraveAdsCreativeNewTabPageAdsDatabaseUtilTest, + DoNotParseAndSaveCreativeAdsWithMissingCampaigns) { + FAIL(); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/internal/creatives/new_tab_page_ads/new_tab_page_ad_builder.cc b/components/brave_ads/core/internal/creatives/new_tab_page_ads/new_tab_page_ad_builder.cc index f58854756f5f..f8f4c5afe23f 100644 --- a/components/brave_ads/core/internal/creatives/new_tab_page_ads/new_tab_page_ad_builder.cc +++ b/components/brave_ads/core/internal/creatives/new_tab_page_ads/new_tab_page_ad_builder.cc @@ -31,17 +31,9 @@ NewTabPageAdInfo BuildNewTabPageAd( ad.advertiser_id = creative_ad.advertiser_id; ad.segment = creative_ad.segment; ad.company_name = creative_ad.company_name; - ad.image_url = creative_ad.image_url; ad.alt = creative_ad.alt; ad.target_url = creative_ad.target_url; - for (const auto& [image_url, focal_point, _] : creative_ad.wallpapers) { - ad.wallpapers.push_back(NewTabPageAdWallpaperInfo{ - .image_url = image_url, - .focal_point = - NewTabPageAdWallpaperFocalPointInfo{focal_point.x, focal_point.y}}); - } - return ad; } diff --git a/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.cc b/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.cc index 4e8827c150d6..c175d3454d71 100644 --- a/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.cc +++ b/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.cc @@ -392,8 +392,8 @@ void CreativeNotificationAds::Migrate( break; } - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -406,16 +406,19 @@ void CreativeNotificationAds::MigrateToV37( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); + // Embeddings are deprecated. DropTable(mojom_db_transaction, "embeddings"); DropTable(mojom_db_transaction, "text_embedding_html_events"); } -void CreativeNotificationAds::MigrateToV45( +void CreativeNotificationAds::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // Recreating the table is safe because it will be repopulated after + // downloading the catalog post-migration. However, after this migration, we + // should not drop the table as it needs to maintain relationships with other + // tables. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } diff --git a/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.h b/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.h index dc1cd75e4efc..b4a7ed01354a 100644 --- a/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.h +++ b/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.h @@ -63,7 +63,7 @@ class CreativeNotificationAds final : public TableInterface { private: static void MigrateToV37( const mojom::DBTransactionInfoPtr& mojom_db_transaction); - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); void Insert(const mojom::DBTransactionInfoPtr& mojom_db_transaction, const CreativeNotificationAdList& creative_ads); diff --git a/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.cc b/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.cc index ff724f2d9c9f..67ce614382f3 100644 --- a/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.cc +++ b/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.cc @@ -11,15 +11,6 @@ namespace brave_ads::database { -void DeleteCreativeNotificationAds() { - const table::CreativeNotificationAds database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete creative notification ads"); - } - })); -} - void SaveCreativeNotificationAds( const CreativeNotificationAdList& creative_ads) { table::CreativeNotificationAds database_table; diff --git a/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.h b/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.h index 18a678353ac8..705e1869be55 100644 --- a/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.h +++ b/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_util.h @@ -10,8 +10,6 @@ namespace brave_ads::database { -void DeleteCreativeNotificationAds(); - void SaveCreativeNotificationAds( const CreativeNotificationAdList& creative_ads); diff --git a/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.cc b/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.cc index 86115965ba57..b2da285eb9da 100644 --- a/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.cc +++ b/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.cc @@ -468,8 +468,8 @@ void CreativePromotedContentAds::Migrate( CHECK(mojom_db_transaction); switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -477,12 +477,14 @@ void CreativePromotedContentAds::Migrate( /////////////////////////////////////////////////////////////////////////////// -void CreativePromotedContentAds::MigrateToV45( +void CreativePromotedContentAds::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // Recreating the table is safe because it will be repopulated after + // downloading the catalog post-migration. However, after this migration, we + // should not drop the table as it needs to maintain relationships with other + // tables. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } diff --git a/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.h b/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.h index 9dfa5fd9d238..c82e54832a6a 100644 --- a/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.h +++ b/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.h @@ -73,7 +73,7 @@ class CreativePromotedContentAds final : public TableInterface { int to_version) override; private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); void Insert(const mojom::DBTransactionInfoPtr& mojom_db_transaction, const CreativePromotedContentAdList& creative_ads); diff --git a/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.cc b/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.cc index bd0a0d4ab47c..766255c97fcb 100644 --- a/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.cc +++ b/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.cc @@ -11,15 +11,6 @@ namespace brave_ads::database { -void DeleteCreativePromotedContentAds() { - const table::CreativePromotedContentAds database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete creative promoted content ads"); - } - })); -} - void SaveCreativePromotedContentAds( const CreativePromotedContentAdList& creative_ads) { table::CreativePromotedContentAds database_table; diff --git a/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.h b/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.h index 359344405eda..9c512348b78c 100644 --- a/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.h +++ b/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_util.h @@ -10,8 +10,6 @@ namespace brave_ads::database { -void DeleteCreativePromotedContentAds(); - void SaveCreativePromotedContentAds( const CreativePromotedContentAdList& creative_ads); diff --git a/components/brave_ads/core/internal/creatives/segments_database_table.cc b/components/brave_ads/core/internal/creatives/segments_database_table.cc index 7406e0945d75..38a4e62fc9c0 100644 --- a/components/brave_ads/core/internal/creatives/segments_database_table.cc +++ b/components/brave_ads/core/internal/creatives/segments_database_table.cc @@ -6,11 +6,15 @@ #include "brave/components/brave_ads/core/internal/creatives/segments_database_table.h" #include +#include +#include #include #include "base/check.h" #include "base/location.h" +#include "base/logging.h" #include "base/strings/string_util.h" +#include "base/values.h" #include "brave/components/brave_ads/core/internal/common/database/database_column_util.h" #include "brave/components/brave_ads/core/internal/common/database/database_table_util.h" #include "brave/components/brave_ads/core/internal/common/database/database_transaction_util.h" @@ -89,8 +93,8 @@ void Segments::Migrate(const mojom::DBTransactionInfoPtr& mojom_db_transaction, CHECK(mojom_db_transaction); switch (to_version) { - case 45: { - MigrateToV45(mojom_db_transaction); + case 46: { + MigrateToV46(mojom_db_transaction); break; } } @@ -98,12 +102,14 @@ void Segments::Migrate(const mojom::DBTransactionInfoPtr& mojom_db_transaction, /////////////////////////////////////////////////////////////////////////////// -void Segments::MigrateToV45( +void Segments::MigrateToV46( const mojom::DBTransactionInfoPtr& mojom_db_transaction) { CHECK(mojom_db_transaction); - // We can safely recreate the table because it will be repopulated after - // downloading the catalog. + // It is safe to recreate the table because it will be repopulated after + // downloading the catalog post-migration. However, after this migration, we + // should not drop the table as it will be used to store data for non-catalog + // ads units and to maintain relationships with other tables. DropTable(mojom_db_transaction, GetTableName()); Create(mojom_db_transaction); } diff --git a/components/brave_ads/core/internal/creatives/segments_database_table.h b/components/brave_ads/core/internal/creatives/segments_database_table.h index f1d346d6bc10..c641fcd9b55d 100644 --- a/components/brave_ads/core/internal/creatives/segments_database_table.h +++ b/components/brave_ads/core/internal/creatives/segments_database_table.h @@ -29,7 +29,7 @@ class Segments final : public TableInterface { int to_version) override; private: - void MigrateToV45(const mojom::DBTransactionInfoPtr& mojom_db_transaction); + void MigrateToV46(const mojom::DBTransactionInfoPtr& mojom_db_transaction); std::string BuildInsertSql(const mojom::DBActionInfoPtr& mojom_db_action, const CreativeAdList& creative_ads) const; diff --git a/components/brave_ads/core/internal/creatives/segments_database_util.cc b/components/brave_ads/core/internal/creatives/segments_database_util.cc deleted file mode 100644 index 3588d2daee3e..000000000000 --- a/components/brave_ads/core/internal/creatives/segments_database_util.cc +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_ads/core/internal/creatives/segments_database_util.h" - -#include "base/functional/bind.h" -#include "brave/components/brave_ads/core/internal/common/logging_util.h" -#include "brave/components/brave_ads/core/internal/creatives/segments_database_table.h" - -namespace brave_ads::database { - -void DeleteSegments() { - const table::Segments database_table; - database_table.Delete(base::BindOnce([](bool success) { - if (!success) { - BLOG(0, "Failed to delete segments"); - } - })); -} - -} // namespace brave_ads::database diff --git a/components/brave_ads/core/internal/creatives/segments_database_util.h b/components/brave_ads/core/internal/creatives/segments_database_util.h deleted file mode 100644 index 50066489af77..000000000000 --- a/components/brave_ads/core/internal/creatives/segments_database_util.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_SEGMENTS_DATABASE_UTIL_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_SEGMENTS_DATABASE_UTIL_H_ - -namespace brave_ads::database { - -void DeleteSegments(); - -} // namespace brave_ads::database - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CREATIVES_SEGMENTS_DATABASE_UTIL_H_ diff --git a/components/brave_ads/core/internal/legacy_migration/database/database_constants.h b/components/brave_ads/core/internal/legacy_migration/database/database_constants.h index 06152e45905b..da2d8355e9f4 100644 --- a/components/brave_ads/core/internal/legacy_migration/database/database_constants.h +++ b/components/brave_ads/core/internal/legacy_migration/database/database_constants.h @@ -8,8 +8,8 @@ namespace brave_ads::database { -inline constexpr int kVersionNumber = 45; -inline constexpr int kCompatibleVersionNumber = 45; +inline constexpr int kVersionNumber = 46; +inline constexpr int kCompatibleVersionNumber = 46; // If the database version number is less than or equal to this value, the // database will be razed and recreated during migration. This should be updated diff --git a/components/brave_ads/core/internal/legacy_migration/database/database_creation.cc b/components/brave_ads/core/internal/legacy_migration/database/database_creation.cc index fb865333aa3d..648cbf9e9aa4 100644 --- a/components/brave_ads/core/internal/legacy_migration/database/database_creation.cc +++ b/components/brave_ads/core/internal/legacy_migration/database/database_creation.cc @@ -19,7 +19,6 @@ #include "brave/components/brave_ads/core/internal/creatives/dayparts_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/geo_targets_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.h" @@ -70,11 +69,6 @@ void Create(const mojom::DBTransactionInfoPtr& mojom_db_transaction) { table::CreativeNewTabPageAds creative_new_tab_page_ads_database_table; creative_new_tab_page_ads_database_table.Create(mojom_db_transaction); - table::CreativeNewTabPageAdWallpapers - creative_new_tab_page_ad_wallpapers_database_table; - creative_new_tab_page_ad_wallpapers_database_table.Create( - mojom_db_transaction); - table::CreativePromotedContentAds creative_promoted_content_ads_database_table; creative_promoted_content_ads_database_table.Create(mojom_db_transaction); diff --git a/components/brave_ads/core/internal/legacy_migration/database/database_migration.cc b/components/brave_ads/core/internal/legacy_migration/database/database_migration.cc index 11be333ffa98..877c2eba1b39 100644 --- a/components/brave_ads/core/internal/legacy_migration/database/database_migration.cc +++ b/components/brave_ads/core/internal/legacy_migration/database/database_migration.cc @@ -19,7 +19,6 @@ #include "brave/components/brave_ads/core/internal/creatives/dayparts_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/geo_targets_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table.h" -#include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table.h" #include "brave/components/brave_ads/core/internal/creatives/promoted_content_ads/creative_promoted_content_ads_database_table.h" @@ -99,11 +98,6 @@ void MigrateToVersion(const mojom::DBTransactionInfoPtr& mojom_db_transaction, creative_new_tab_page_ads_database_table.Migrate(mojom_db_transaction, to_version); - table::CreativeNewTabPageAdWallpapers - creative_new_tab_page_ad_wallpapers_database_table; - creative_new_tab_page_ad_wallpapers_database_table.Migrate( - mojom_db_transaction, to_version); - table::CreativePromotedContentAds creative_promoted_content_ads_database_table; creative_promoted_content_ads_database_table.Migrate(mojom_db_transaction, diff --git a/components/brave_ads/core/internal/serving/eligible_ads/pipelines/new_tab_page_ads/eligible_new_tab_page_ads_v2.cc b/components/brave_ads/core/internal/serving/eligible_ads/pipelines/new_tab_page_ads/eligible_new_tab_page_ads_v2.cc index 81f7a764078e..3135f6da4bf8 100644 --- a/components/brave_ads/core/internal/serving/eligible_ads/pipelines/new_tab_page_ads/eligible_new_tab_page_ads_v2.cc +++ b/components/brave_ads/core/internal/serving/eligible_ads/pipelines/new_tab_page_ads/eligible_new_tab_page_ads_v2.cc @@ -175,10 +175,9 @@ void EligibleNewTabPageAdsV2::ApplyConditionMatcher( TRACE_EVENT(kTraceEventCategory, "ApplyConditionMatcher", "creative_ads", creative_ads.size()); - std::erase_if(creative_ads, [this](const auto& creative_ad) { - return creative_ad.wallpapers.size() != 1 || - !MatchConditions(&pref_provider_, - creative_ad.wallpapers[0].condition_matchers); + std::erase_if(creative_ads, [this]( + const CreativeNewTabPageAdInfo& creative_ad) { + return !MatchConditions(&pref_provider_, creative_ad.condition_matchers); }); } diff --git a/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_unittest.cc b/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_unittest.cc index b12ca316735d..2f8376d0da9e 100644 --- a/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_unittest.cc +++ b/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_unittest.cc @@ -89,28 +89,6 @@ TEST_F(BraveAdsNewTabPageAdServingTest, ServeAd) { run_loop.Run(); } -TEST_F(BraveAdsNewTabPageAdServingTest, DoNotServeAdIfMissingWallpapers) { - // Arrange - test::ForcePermissionRules(); - - CreativeNewTabPageAdInfo creative_ad = - test::BuildCreativeNewTabPageAd(/*should_generate_random_uuids=*/true); - creative_ad.wallpapers.clear(); - database::SaveCreativeNewTabPageAds({creative_ad}); - - // Act & Assert - EXPECT_CALL(delegate_mock_, OnOpportunityAroseToServeNewTabPageAd); - - EXPECT_CALL(delegate_mock_, OnFailedToServeNewTabPageAd); - - base::MockCallback callback; - base::RunLoop run_loop; - EXPECT_CALL(callback, Run(/*ad=*/::testing::Eq(std::nullopt))) - .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure())); - MaybeServeAd(callback.Get()); - run_loop.Run(); -} - TEST_F(BraveAdsNewTabPageAdServingTest, DoNotServeAdIfNoEligibleAdsFound) { // Arrange test::ForcePermissionRules(); diff --git a/components/brave_ads/core/public/BUILD.gn b/components/brave_ads/core/public/BUILD.gn index 8d5d10f35482..3c95be16cd32 100644 --- a/components/brave_ads/core/public/BUILD.gn +++ b/components/brave_ads/core/public/BUILD.gn @@ -12,10 +12,9 @@ source_set("headers") { "ad_units/inline_content_ad/inline_content_ad_info.h", "ad_units/inline_content_ad/inline_content_ad_value_util.h", "ad_units/new_tab_page_ad/new_tab_page_ad_constants.h", + "ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.h", "ad_units/new_tab_page_ad/new_tab_page_ad_info.h", "ad_units/new_tab_page_ad/new_tab_page_ad_value_util.h", - "ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_focal_point_info.h", - "ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_info.h", "ad_units/notification_ad/notification_ad_constants.h", "ad_units/notification_ad/notification_ad_feature.h", "ad_units/notification_ad/notification_ad_info.h", diff --git a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_constants.h b/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_constants.h index 397f73048966..ac0717f53ed6 100644 --- a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_constants.h +++ b/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_constants.h @@ -18,11 +18,6 @@ inline constexpr char kNewTabPageAdAdvertiserIdKey[] = "advertiser_id"; inline constexpr char kNewTabPageAdSegmentKey[] = "segment"; inline constexpr char kNewTabPageAdCompanyNameKey[] = "company_name"; inline constexpr char kNewTabPageAdAltKey[] = "alt"; -inline constexpr char kNewTabPageAdImageUrlKey[] = "image_url"; -inline constexpr char kNewTabPageAdFocalPointKey[] = "focal_point"; -inline constexpr char kNewTabPageAdFocalPointXKey[] = "x"; -inline constexpr char kNewTabPageAdFocalPointYKey[] = "y"; -inline constexpr char kNewTabPageAdWallpapersKey[] = "wallpapers"; inline constexpr char kNewTabPageAdTargetUrlKey[] = "target_url"; } // namespace brave_ads diff --git a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.h b/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.h new file mode 100644 index 000000000000..8c0cf459cb31 --- /dev/null +++ b/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_EVENT_TYPE_UTIL_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_EVENT_TYPE_UTIL_H_ + +#include +#include + +#include "brave/components/brave_ads/core/mojom/brave_ads.mojom-forward.h" + +namespace brave_ads { + +std::optional +ToMojomNewTabPageAdEventType(const std::string& event_type); + +} // namespace brave_ads + +#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_EVENT_TYPE_UTIL_H_ diff --git a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_info.h b/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_info.h index ec3c9ad49677..579c2a41cfa3 100644 --- a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_info.h +++ b/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_info.h @@ -9,9 +9,7 @@ #include #include "brave/components/brave_ads/core/public/ad_units/ad_info.h" -#include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_info.h" #include "brave/components/brave_ads/core/public/export.h" -#include "url/gurl.h" namespace brave_ads { @@ -31,9 +29,7 @@ struct ADS_EXPORT NewTabPageAdInfo final : AdInfo { [[nodiscard]] bool IsValid() const; std::string company_name; - GURL image_url; std::string alt; - NewTabPageAdWallpaperList wallpapers; }; } // namespace brave_ads diff --git a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_focal_point_info.h b/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_focal_point_info.h deleted file mode 100644 index c083c87761bc..000000000000 --- a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_focal_point_info.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ - -#include "brave/components/brave_ads/core/public/export.h" - -namespace brave_ads { - -struct ADS_EXPORT NewTabPageAdWallpaperFocalPointInfo final { - bool operator==(const NewTabPageAdWallpaperFocalPointInfo&) const = default; - - int x = 0; - int y = 0; -}; - -} // namespace brave_ads - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_WALLPAPER_FOCAL_POINT_INFO_H_ diff --git a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_info.h b/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_info.h deleted file mode 100644 index 6235c3a2e86b..000000000000 --- a/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_info.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2021 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ -#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ - -#include - -#include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_wallpaper_focal_point_info.h" -#include "brave/components/brave_ads/core/public/export.h" -#include "url/gurl.h" - -namespace brave_ads { - -struct ADS_EXPORT NewTabPageAdWallpaperInfo final { - bool operator==(const NewTabPageAdWallpaperInfo&) const = default; - - GURL image_url; - NewTabPageAdWallpaperFocalPointInfo focal_point; -}; - -using NewTabPageAdWallpaperList = std::vector; - -} // namespace brave_ads - -#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_PUBLIC_AD_UNITS_NEW_TAB_PAGE_AD_NEW_TAB_PAGE_AD_WALLPAPER_INFO_H_ diff --git a/components/brave_ads/core/public/ads.h b/components/brave_ads/core/public/ads.h index 2859432bd017..fcfa4b3c2f77 100644 --- a/components/brave_ads/core/public/ads.h +++ b/components/brave_ads/core/public/ads.h @@ -92,6 +92,12 @@ class ADS_EXPORT Ads { mojom::InlineContentAdEventType mojom_ad_event_type, TriggerAdEventCallback callback) = 0; + // Called to parse and save creative new tab page ads. The callback takes one + // argument - `bool` is set to `true` if successful otherwise `false`. + virtual void ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) = 0; + // Called to serve a new tab page ad. The callback takes one argument - // `NewTabPageAdInfo` containing the info for the ad. virtual void MaybeServeNewTabPageAd( diff --git a/components/brave_ads/core/public/ads_callback.h b/components/brave_ads/core/public/ads_callback.h index 962353decb8d..0f29f7923e3a 100644 --- a/components/brave_ads/core/public/ads_callback.h +++ b/components/brave_ads/core/public/ads_callback.h @@ -29,9 +29,10 @@ using GetDiagnosticsCallback = using GetStatementOfAccountsCallback = base::OnceCallback; +using ParseAndSaveCreativeNewTabPageAdsCallback = + base::OnceCallback; using MaybeServeNewTabPageAdCallback = base::OnceCallback ad)>; - using MaybeServeInlineContentAdCallback = base::OnceCallback ad)>; diff --git a/components/brave_ads/core/test/BUILD.gn b/components/brave_ads/core/test/BUILD.gn index bfad995e665d..b5282c8c557d 100644 --- a/components/brave_ads/core/test/BUILD.gn +++ b/components/brave_ads/core/test/BUILD.gn @@ -164,6 +164,7 @@ source_set("brave_ads_unit_tests") { "//brave/components/brave_ads/core/internal/ad_units/inline_content_ad/inline_content_ad_test_util.cc", "//brave/components/brave_ads/core/internal/ad_units/inline_content_ad/inline_content_ad_test_util.h", "//brave/components/brave_ads/core/internal/ad_units/inline_content_ad/inline_content_ad_value_util_unittest.cc", + "//brave/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util_unittest.cc", "//brave/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_feature_unittest.cc", "//brave/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_info_unittest.cc", "//brave/components/brave_ads/core/internal/ad_units/new_tab_page_ad/new_tab_page_ad_test.cc", @@ -353,6 +354,7 @@ source_set("brave_ads_unit_tests") { "//brave/components/brave_ads/core/internal/creatives/creative_ad_test_util.cc", "//brave/components/brave_ads/core/internal/creatives/creative_ad_test_util.h", "//brave/components/brave_ads/core/internal/creatives/creative_ads_database_table_unittest.cc", + "//brave/components/brave_ads/core/internal/creatives/creative_ads_database_table_util_unittest.cc", "//brave/components/brave_ads/core/internal/creatives/dayparts_database_table_unittest.cc", "//brave/components/brave_ads/core/internal/creatives/geo_targets_database_table_unittest.cc", "//brave/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ad_test_util.cc", @@ -361,9 +363,9 @@ source_set("brave_ads_unit_tests") { "//brave/components/brave_ads/core/internal/creatives/inline_content_ads/creative_inline_content_ads_database_table_unittest.cc", "//brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_test_util.cc", "//brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_test_util.h", - "//brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ad_wallpapers_database_table_unittest.cc", "//brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table_test.cc", "//brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_table_unittest.cc", + "//brave/components/brave_ads/core/internal/creatives/new_tab_page_ads/creative_new_tab_page_ads_database_util_unittest.cc", "//brave/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ad_test_util.cc", "//brave/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ad_test_util.h", "//brave/components/brave_ads/core/internal/creatives/notification_ads/creative_notification_ads_database_table_test.cc", diff --git a/components/brave_ads/core/test/data/catalog_with_multiple_campaigns.json b/components/brave_ads/core/test/data/catalog_with_multiple_campaigns.json index aef439cad0d9..7e71e3f27d8c 100644 --- a/components/brave_ads/core/test/data/catalog_with_multiple_campaigns.json +++ b/components/brave_ads/core/test/data/catalog_with_multiple_campaigns.json @@ -20,32 +20,6 @@ "targetUrl": "https://brave.com/1/notification_ad" } }, - { - "creativeInstanceId": "7ff400b9-7f8a-46a8-89f1-cb386612edcf", - "type": { - "code": "new_tab_page_all_v1", - "platform": "all", - "name": "new_tab_page", - "version": 1 - }, - "payload": { - "logo": { - "alt": "Test New Tab Page Ad Campaign 1", - "imageUrl": "https://brave.com/1/test.jpg", - "companyName": "New Tab Page 1", - "destinationUrl": "https://brave.com/1/new_tab_page_ad" - }, - "wallpapers": [ - { - "focalPoint": { - "x": 1200, - "y": 1400 - }, - "imageUrl": "https://brave.com/1/test2.jpg" - } - ] - } - }, { "creativeInstanceId": "60001aa5-9368-45d2-81fc-e69887d278c5", "type": { @@ -161,38 +135,6 @@ "targetUrl": "https://brave.com/2/notification_ad" } }, - { - "creativeInstanceId": "3dfe54d0-80b7-48d7-9bcc-3c77a912f583", - "type": { - "code": "new_tab_page_all_v1", - "platform": "all", - "name": "new_tab_page", - "version": 1 - }, - "payload": { - "logo": { - "alt": "Test New Tab Page Ad Campaign 2", - "imageUrl": "https://brave.com/2/test.jpg", - "companyName": "New Tab Page 2", - "destinationUrl": "https://brave.com/2/new_tab_page_ad" - }, - "wallpapers": [ - { - "conditionMatchers": [ - { - "prefPath": "brave.today.opted_in", - "condition": "1" - } - ], - "focalPoint": { - "x": 1000, - "y": 1200 - }, - "imageUrl": "https://brave.com/2/test2.jpg" - } - ] - } - }, { "creativeInstanceId": "9f2f49ab-77d7-4e99-9428-472dc8e04f90", "type": { diff --git a/components/brave_ads/core/test/data/catalog_with_single_campaign.json b/components/brave_ads/core/test/data/catalog_with_single_campaign.json index 02f2d9552ca4..129e8d7b103e 100644 --- a/components/brave_ads/core/test/data/catalog_with_single_campaign.json +++ b/components/brave_ads/core/test/data/catalog_with_single_campaign.json @@ -20,32 +20,6 @@ "targetUrl": "https://brave.com/1/notification_ad" } }, - { - "creativeInstanceId": "7ff400b9-7f8a-46a8-89f1-cb386612edcf", - "type": { - "code": "new_tab_page_all_v1", - "platform": "all", - "name": "new_tab_page", - "version": 1 - }, - "payload": { - "logo": { - "alt": "Test New Tab Page Ad Campaign 1", - "imageUrl": "https://brave.com/1/test.jpg", - "companyName": "New Tab Page 1", - "destinationUrl": "https://brave.com/1/new_tab_page_ad" - }, - "wallpapers": [ - { - "focalPoint": { - "x": 1200, - "y": 1400 - }, - "imageUrl": "https://brave.com/1/test2.jpg" - } - ] - } - }, { "creativeInstanceId": "60001aa5-9368-45d2-81fc-e69887d278c5", "type": { diff --git a/components/brave_ads/core/test/data/url_responses/catalog.json b/components/brave_ads/core/test/data/url_responses/catalog.json index 638a304e8883..289ec2595520 100644 --- a/components/brave_ads/core/test/data/url_responses/catalog.json +++ b/components/brave_ads/core/test/data/url_responses/catalog.json @@ -106,74 +106,6 @@ "priority": 1, "ptr": 1.0 }, - { - "creativeSets": [ - { - "creatives": [ - { - "creativeInstanceId": "7ff400b9-7f8a-46a8-89f1-cb386612edcf", - "type": { - "code": "new_tab_page_all_v1", - "platform": "all", - "name": "new_tab_page", - "version": 1 - }, - "payload": { - "logo": { - "alt": "This is a test NTP creative", - "imageUrl": "https://brave.com/test.jpg", - "companyName": "Brave", - "destinationUrl": "https://brave.com" - }, - "wallpapers": [ - { - "conditionMatchers": [ - { - "prefPath": "brave.today.opted_in", - "condition": "1" - } - ], - "focalPoint": { - "x": 1200, - "y": 1400 - }, - "imageUrl": "https://brave.com/test2.jpg" - } - ] - } - } - ], - "segments": [ - { - "code": "yNl0N-ers2", - "name": "technology & computing" - } - ], - "oses": [], - "conversions": [], - "creativeSetId": "25a11ff2-5dd2-4629-95f0-b717454911e8", - "perDay": 5, - "perWeek": 6, - "perMonth": 7, - "totalMax": 100, - "value": "1.0" - } - ], - "dayParts": [], - "geoTargets": [ - { - "code": "US", - "name": "United States" - } - ], - "campaignId": "630aef4b-ec12-4339-8df7-adc66926a4fa", - "startAt": "", - "endAt": "", - "dailyCap": 10, - "advertiserId": "403127e2-dc50-4ece-b25d-c1ea3f7cb634", - "priority": 1, - "ptr": 1.0 - }, { "creativeSets": [ { diff --git a/components/brave_ads/core/test/data/url_responses/catalog_with_new_tab_page_ad.json b/components/brave_ads/core/test/data/url_responses/catalog_with_new_tab_page_ad.json deleted file mode 100644 index 797f3c7afcc8..000000000000 --- a/components/brave_ads/core/test/data/url_responses/catalog_with_new_tab_page_ad.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "version": 9, - "ping": 7200000, - "campaigns": [ - { - "creativeSets": [ - { - "creatives": [ - { - "creativeInstanceId": "546fe7b0-5047-4f28-a11c-81f14edcf0f6", - "type": { - "code": "new_tab_page_all_v1", - "platform": "all", - "name": "new_tab_page", - "version": 1 - }, - "payload": { - "logo": { - "alt": "Test Alt", - "imageUrl": "https://brave.com/image.jpg", - "companyName": "Test Company Name", - "destinationUrl": "https://brave.com" - }, - "wallpapers": [ - { - "conditionMatchers": [ - { - "prefPath": "brave.today.opted_in", - "condition": "1" - } - ], - "focalPoint": { - "x": 1200, - "y": 1400 - }, - "imageUrl": "https://brave.com/wallpaper_1.jpg" - } - ] - } - } - ], - "segments": [ - { - "code": "Svp7l-zGN", - "name": "untargeted" - } - ], - "oses": [], - "conversions": [ - { - "observationWindow": 30, - "urlPattern": "https://www.brave.com/*" - } - ], - "creativeSetId": "340c927f-696e-4060-9933-3eafc56c3f31", - "perDay": 1, - "perWeek": 1, - "perMonth": 1, - "totalMax": 1, - "value": "1.0" - } - ], - "dayParts": [], - "geoTargets": [ - { - "code": "US", - "name": "United States" - } - ], - "campaignId": "27a624a1-9c80-494a-bf1b-af327b563f85", - "startAt": "", - "endAt": "", - "dailyCap": 1, - "advertiserId": "a437c7f3-9a48-4fe8-b37b-99321bea93fe", - "priority": 1, - "ptr": 1.0 - } - ], - "catalogId": "29e5c8bc0ba319069980bb390d8e8f9b58c05a20" -} diff --git a/components/brave_new_tab_ui/api/wallpaper.ts b/components/brave_new_tab_ui/api/wallpaper.ts index 41cb2ceec518..9879a3810046 100644 --- a/components/brave_new_tab_ui/api/wallpaper.ts +++ b/components/brave_new_tab_ui/api/wallpaper.ts @@ -16,3 +16,7 @@ export function registerViewCount (): Promise { export function brandedWallpaperLogoClicked (data: NewTab.BrandedWallpaper | undefined) { chrome.send('brandedWallpaperLogoClicked', [data]) } + +export function triggerSponsoredRichMediaAdEvent(data: NewTab.BrandedWallpaper | undefined, adEventType: NewTab.SponsoredRichMediaEventType) { + chrome.send('triggerSponsoredRichMediaAdEvent', [data, adEventType]) +} diff --git a/components/brave_new_tab_ui/components/default/page/index.tsx b/components/brave_new_tab_ui/components/default/page/index.tsx index 26e6b4326a57..397dba7590ce 100644 --- a/components/brave_new_tab_ui/components/default/page/index.tsx +++ b/components/brave_new_tab_ui/components/default/page/index.tsx @@ -26,9 +26,13 @@ interface HasImageProps { colorForBackground?: string } +interface HasSponsoredRichMediaProps { + hasSponsoredRichMediaBackground: boolean +} + type AppProps = { dataIsReady: boolean -} & HasImageProps +} & HasImageProps & HasSponsoredRichMediaProps type PageProps = { showClock: boolean @@ -36,7 +40,7 @@ type PageProps = { showCryptoContent: boolean showTopSites: boolean showBrandedWallpaper: boolean -} & HasImageProps +} & HasImageProps & HasSponsoredRichMediaProps function getItemRowCount(p: PageProps): number { let right = (p.showClock ? 1 : 0) + (p.showCryptoContent ? 2 : 0) @@ -108,6 +112,15 @@ const StyledPage = styled('div') ` flex-direction: column; align-items: center; } + + ${p => p.hasSponsoredRichMediaBackground && css` + // Allow clicks to pass through to background + pointer-events: none; + // Restore click events for child elements + & > * { + pointer-events: auto; + } + `}; ` export const Page: React.FunctionComponent> = (props) => { @@ -314,7 +327,11 @@ export const FooterContent = styled('div')` ` // Gets the value of the CSS `background` property. -function getBackground(p: HasImageProps) { +function getBackground(p: HasImageProps & HasSponsoredRichMediaProps) { + if (p.hasSponsoredRichMediaBackground) { + return '' + } + if (!p.hasImage) { return p.colorForBackground || `linear-gradient(to bottom right, #4D54D1, #A51C7B 50%, #EE4A37 100%)` } @@ -333,7 +350,7 @@ function getBackground(p: HasImageProps) { return '' } -function getPageBackground(p: HasImageProps) { +function getPageBackground(p: HasImageProps & HasSponsoredRichMediaProps) { // Page background is duplicated since a backdrop-filter's // ancestor which has blur must also have background. // In our case, Widgets are the backdrop-filter element @@ -343,7 +360,7 @@ function getPageBackground(p: HasImageProps) { // Page's ancestor: App. // Use a :before pseudo element so that we can fade the image // in when it is loaded. - return css` + return css` &:before { pointer-events: none; content: ""; @@ -367,7 +384,7 @@ function getPageBackground(p: HasImageProps) { ` } -export const App = styled('div') ` +export const App = styled('div') ` --bg-opacity: ${p => p.imageHasLoaded ? 1 : 0}; position: relative; box-sizing: border-box; diff --git a/components/brave_new_tab_ui/containers/newTab/index.tsx b/components/brave_new_tab_ui/containers/newTab/index.tsx index 9fc43cf8f5a6..496f7defe737 100644 --- a/components/brave_new_tab_ui/containers/newTab/index.tsx +++ b/components/brave_new_tab_ui/containers/newTab/index.tsx @@ -8,7 +8,9 @@ import * as React from 'react' // Components import getNTPBrowserAPI from '../../api/background' import { addNewTopSite, editTopSite } from '../../api/topSites' -import { brandedWallpaperLogoClicked } from '../../api/wallpaper' +import { + brandedWallpaperLogoClicked, triggerSponsoredRichMediaAdEvent +} from '../../api/wallpaper' import { BraveTalkWidget as BraveTalk, Clock, EditTopSite, OverrideReadabilityColor, RewardsWidget as Rewards, SearchPromotion, VPNWidget } from '../../components/default' @@ -46,6 +48,9 @@ import Icon from '@brave/leo/react/icon' import * as style from './style' import { defaultState } from '../../storage/new_tab_storage' import { EngineContextProvider } from '../../components/search/EngineContext' +import { + SponsoredRichMediaBackgroundInfo, SponsoredRichMediaBackground +} from './sponsored_rich_media_background' const BraveNewsPeek = React.lazy(() => import('../../../brave_news/browser/resources/Peek')) const SearchPlaceholder = React.lazy(() => import('../../components/search/SearchPlaceholder')) @@ -85,7 +90,11 @@ function GetBackgroundImageSrc (props: Props) { (!props.newTabData.brandedWallpaper || props.newTabData.brandedWallpaper.isSponsored)) { return undefined } + if (props.newTabData.brandedWallpaper) { + if (props.newTabData.brandedWallpaper.type !== 'image') { + return undefined + } const wallpaperData = props.newTabData.brandedWallpaper if (wallpaperData.wallpaperImageUrl) { return wallpaperData.wallpaperImageUrl @@ -100,6 +109,27 @@ function GetBackgroundImageSrc (props: Props) { return undefined } +function GetSponsoredRichMediaBackground(props: Props): SponsoredRichMediaBackgroundInfo | undefined { + if (!props.newTabData.showBackgroundImage && + (!props.newTabData.brandedWallpaper || props.newTabData.brandedWallpaper.isSponsored)) { + return undefined + } + + if (props.newTabData.brandedWallpaper && props.newTabData.brandedWallpaper.type === 'richMedia') { + const wallpaperData = props.newTabData.brandedWallpaper + if (wallpaperData.wallpaperImageUrl) { + return { + url: wallpaperData.wallpaperImageUrl, + placementId: wallpaperData.wallpaperId, + creativeInstanceId: wallpaperData.creativeInstanceId, + targetUrl: wallpaperData.logo.destinationUrl + } + } + } + + return undefined +} + function GetShouldShowSearchPromotion (props: Props, showSearchPromotion: boolean) { if (GetIsShowingBrandedWallpaper(props)) { return false } @@ -141,6 +171,7 @@ class NewTabPage extends React.Component { braveNewsPromptTimerId: number hasInitBraveNews: boolean = false imageSource?: string = undefined + sponsoredRichMediaBackgroundInfo?: SponsoredRichMediaBackgroundInfo = undefined timerIdForBrandedWallpaperNotification?: number = undefined onVisiblityTimerExpired = () => { this.dismissBrandedWallpaperNotification(false) @@ -152,6 +183,8 @@ class NewTabPage extends React.Component { // if a notification is open at component mounting time, close it this.props.actions.showTilesRemovedNotice(false) this.imageSource = GetBackgroundImageSrc(this.props) + this.sponsoredRichMediaBackgroundInfo = GetSponsoredRichMediaBackground(this.props) + this.trackCachedImage() if (GetShouldShowBrandedWallpaperNotification(this.props)) { this.trackBrandedWallpaperNotificationAutoDismiss() @@ -182,8 +215,20 @@ class NewTabPage extends React.Component { if (newImageSource && oldImageSource !== newImageSource) { this.trackCachedImage() } - if (oldImageSource && - !newImageSource) { + + const oldSponsoredRichMediaBackground = GetSponsoredRichMediaBackground(prevProps) + const newSponsoredRichMediaBackground = GetSponsoredRichMediaBackground(this.props) + this.sponsoredRichMediaBackgroundInfo = newSponsoredRichMediaBackground + if (newSponsoredRichMediaBackground && + oldSponsoredRichMediaBackground?.url !== newSponsoredRichMediaBackground?.url) { + if (this.state.backgroundHasLoaded) { + console.debug('Resetting to sponsored rich media background') + this.setState({ backgroundHasLoaded: false }) + } + } + + if ((oldImageSource && !newImageSource) || + (oldSponsoredRichMediaBackground && !newSponsoredRichMediaBackground)) { // reset loaded state console.debug('reset image loaded state due to removing image source') this.setState({ backgroundHasLoaded: false }) @@ -615,6 +660,7 @@ class NewTabPage extends React.Component { } const hasImage = this.imageSource !== undefined + const hasSponsoredRichMediaBackground = this.sponsoredRichMediaBackgroundInfo !== undefined const isShowingBrandedWallpaper = !!newTabData.brandedWallpaper const hasWallpaperInfo = newTabData.backgroundWallpaper?.type === 'brave' @@ -648,14 +694,38 @@ class NewTabPage extends React.Component { imageSrc={this.imageSource} imageHasLoaded={this.state.backgroundHasLoaded} colorForBackground={colorForBackground} + hasSponsoredRichMediaBackground={hasSponsoredRichMediaBackground} data-show-news-prompt={((this.state.backgroundHasLoaded || colorForBackground) && this.state.isPromptingBraveNews && !defaultState.featureFlagBraveNewsFeedV2Enabled) ? true : undefined}> + + { + hasSponsoredRichMediaBackground && + { + if (!this.state.backgroundHasLoaded) { + this.setState({ backgroundHasLoaded: true }) + } + }} + onEventReported={(adEventType: NewTab.SponsoredRichMediaEventType) => { + triggerSponsoredRichMediaAdEvent(this.props.newTabData.brandedWallpaper, adEventType) + + if (this.sponsoredRichMediaBackgroundInfo && adEventType === 'click') { + window.open(this.sponsoredRichMediaBackgroundInfo.targetUrl, '_self', 'noopener,noreferrer'); + } + } + } + /> + } + { /> } - {newTabData.brandedWallpaper?.isSponsored && - + {newTabData.brandedWallpaper?.isSponsored + && newTabData.brandedWallpaper.type !== 'richMedia' + && + } { gridSitesData.shouldShowSiteRemovedNotification @@ -717,6 +789,7 @@ class NewTabPage extends React.Component { {isShowingBrandedWallpaper && newTabData.brandedWallpaper && newTabData.brandedWallpaper.logo && + !hasSponsoredRichMediaBackground && void + onLoaded: () => void +} + +const iframeAllow = ` + accelerometer 'none'; + ambient-light-sensor 'none'; + camera 'none'; + display-capture 'none'; + document-domain 'none'; + fullscreen 'none'; + geolocation 'none'; + gyroscope 'none'; + magnetometer 'none'; + microphone 'none'; + midi 'none'; + payment 'none'; + publickey-credentials-get 'none'; + usb 'none' +` + +const SponsoredRichMediaBackgroundIframe = styled('iframe') ` + opacity: ${p => p.sponsoredRichMediaBackgroundHasLoaded ? 1 : 0}; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: none; + z-index: 0; +` + +/// We expect the event data to be of the following format: +/// { +/// type: 'richMediaEvent', +/// value: 'click' +/// } +function getEventType(event: MessageEvent): NewTab.SponsoredRichMediaEventType | undefined { + if (!event.data || event.data.type !== 'richMediaEvent') { + return undefined + } + + if (event.data.value === 'click' || event.data.value === 'mediaPlay' + || event.data.value === 'media25' || event.data.value === 'media100') { + return event.data.value as NewTab.SponsoredRichMediaEventType + } + + return undefined +} + +export function SponsoredRichMediaBackground (props: Props) { + const iframeRef = React.useRef(null) + const { sponsoredRichMediaBackgroundInfo } = props + + if (!sponsoredRichMediaBackgroundInfo) { + return null + } + + React.useEffect(() => { + const listener = (event: MessageEvent) => { + if (!iframeRef.current) { + return + } + + const { contentWindow } = iframeRef.current + if (!event.source || event.source !== contentWindow || !event.data) { + return + } + + const eventType = getEventType(event) + if (!eventType) { + return + } + + props.onEventReported(eventType) + } + + window.addEventListener('message', listener) + return () => { window.removeEventListener('message', listener) } + }, [props]) + + return ( + { props.onLoaded() }}> + + ) +} diff --git a/components/brave_new_tab_ui/stories/default/data/brandedWallpaper.ts b/components/brave_new_tab_ui/stories/default/data/brandedWallpaper.ts index fd1ced28bd6c..561c43c9dcff 100644 --- a/components/brave_new_tab_ui/stories/default/data/brandedWallpaper.ts +++ b/components/brave_new_tab_ui/stories/default/data/brandedWallpaper.ts @@ -6,6 +6,7 @@ import wallpaperImageUrl from '../../../../img/newtab/dummy-branded-wallpaper/ba import brandingImageUrl from '../../../../img/newtab/dummy-branded-wallpaper/logo.png' const dummyWallpaper: NewTab.BrandedWallpaper = { + type: 'image', isSponsored: true, wallpaperImageUrl, creativeInstanceId: '12345abcde', diff --git a/components/constants/webui_url_constants.h b/components/constants/webui_url_constants.h index a9218b672500..2d98492aa9a4 100644 --- a/components/constants/webui_url_constants.h +++ b/components/constants/webui_url_constants.h @@ -96,6 +96,11 @@ inline constexpr char kRewriterUIHost[] = "rewriter"; inline constexpr char16_t kTransactionSimulationLearnMoreURL[] = u"https://github.com/brave/brave-browser/wiki/Transaction-Simulation"; +inline constexpr char kNTPSponsoredRichMediaUrl[] = + "chrome-untrusted://rich-media/"; + +inline constexpr char kChromeUINewTabURL[] = "chrome://newtab/"; + // Hosts that are allowed to be installed as PWAs, which is usually // a blocked action for WebUIs. In Chromium, the "password-manager" host // is already allowed. diff --git a/components/definitions/newTab.d.ts b/components/definitions/newTab.d.ts index 5dd451ee8771..792d2f09b31d 100644 --- a/components/definitions/newTab.d.ts +++ b/components/definitions/newTab.d.ts @@ -39,7 +39,10 @@ declare namespace NewTab { destinationUrl: string } + export type BrandedWallpaperType = 'image' | 'richMedia' + export type BrandedWallpaper = { + type: BrandedWallpaperType wallpaperImageUrl: string isSponsored: boolean creativeInstanceId: string @@ -47,6 +50,8 @@ declare namespace NewTab { logo: BrandedWallpaperLogo } + export type SponsoredRichMediaEventType = 'click' | 'mediaPlay' | 'media25' | 'media100' + export interface Wallpaper { backgroundWallpaper: BackgroundWallpaper brandedWallpaper?: BrandedWallpaper diff --git a/components/ntp_background_images/browser/BUILD.gn b/components/ntp_background_images/browser/BUILD.gn index cbe8fefd4765..ef0fcce4bdbe 100644 --- a/components/ntp_background_images/browser/BUILD.gn +++ b/components/ntp_background_images/browser/BUILD.gn @@ -34,6 +34,8 @@ static_library("browser") { "ntp_background_images_source.h", "ntp_sponsored_images_source.cc", "ntp_sponsored_images_source.h", + "ntp_sponsored_rich_media_source.cc", + "ntp_sponsored_rich_media_source.h", "view_counter_model.cc", "view_counter_model.h", "view_counter_service.cc", @@ -46,6 +48,7 @@ static_library("browser") { "//brave/components/brave_ads/core", "//brave/components/brave_component_updater/browser", "//brave/components/brave_rewards/common", + "//brave/components/constants", "//brave/components/l10n/common", "//brave/components/ntp_background_images/buildflags", "//brave/components/ntp_background_images/common", @@ -70,6 +73,7 @@ static_library("browser") { "//brave/components/brave_referrals/browser", "//content/public/browser", "//content/public/common", + "//net", ] } diff --git a/components/ntp_background_images/browser/ntp_background_images_service.cc b/components/ntp_background_images/browser/ntp_background_images_service.cc index 93a6ed8a74a1..8bf49dfe9313 100644 --- a/components/ntp_background_images/browser/ntp_background_images_service.cc +++ b/components/ntp_background_images/browser/ntp_background_images_service.cc @@ -5,7 +5,6 @@ #include "brave/components/ntp_background_images/browser/ntp_background_images_service.h" -#include #include #include #include @@ -44,6 +43,7 @@ namespace ntp_background_images { namespace { constexpr char kNTPManifestFile[] = "photo.json"; +constexpr char kNTPSponsoredManifestFile[] = "campaigns.json"; constexpr char kNTPSRMappingTableFile[] = "mapping-table.json"; constexpr char kNTPSRMappingTableComponentPublicKey[] = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp7IWv7wzH/KLrxx7BKWOIIUMDylQNzxwM5Fig2WHc16BoMW9Kaya/g17Bpfp0YIvxdcmDBcB9kFALqQLxi1WQfa9d7YxqcmAGUKo407RMwEa6dQVkIPMFz2ZPGSfFgr526gYOqWh3Q4h8oN94qxBLgFyT25SMK5zQDGyq96ntME4MQRNwpDBUv7DDK7Npwe9iE8cBgzYTvf0taAFn2ZZi1RhS0RzpdynucpKosnc0sVBLTXy+HDvnMr+77T48zM0YmpjIh8Qmrp9CNbKzZUsZzNfnHpL9IZnjwQ51EOYdPGX2r1obChVZN19HzpK5scZEMRKoCMfCepWpEkMSIoPzQIDAQAB"; // NOLINT @@ -59,28 +59,19 @@ std::string GetMappingTableData(const base::FilePath& installed_dir) { return contents; } -// If registered component is for sponsored images wallpaper, it has photo.json -// in |installed_dir|. Otherwise, it has data.json for super referral. -// This methods cache super referral's favicon data because that favicon images -// could be used after campaign ends. -// And return manifest json string. -std::string HandleComponentData(const base::FilePath& installed_dir) { - base::FilePath json_path = installed_dir.AppendASCII(kNTPManifestFile); - std::string contents; - - if (json_path.empty()) { - // NTP sponsored component should have photo.json always but anything can - // happen outside of browser. Handle it gracefully instead of crash. - VLOG(6) << "Cannot find valid NTP Images component manifest file in: " - << installed_dir; - return contents; - } +// If registered component is for sponsored images wallpaper, it has +// campaigns.json in |installed_dir|. Otherwise, it has data.json for super +// referral. This methods cache super referral's favicon data because that +// favicon images could be used after campaign ends. And return manifest json +// string. +std::string HandleComponentData(const base::FilePath& installed_dir, + const std::string& manifest_file) { + const base::FilePath file_path = installed_dir.AppendASCII(manifest_file); - bool success = base::ReadFileToString(json_path, &contents); + std::string contents; + const bool success = base::ReadFileToString(file_path, &contents); if (!success || contents.empty()) { - VLOG(6) << "Cannot read NTP Images component manifest file at: " - << json_path; - return contents; + VLOG(6) << "Cannot read NTP Images component manifest file"; } return contents; @@ -503,7 +494,7 @@ void NTPBackgroundImagesService::OnComponentReady( base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock()}, - base::BindOnce(&HandleComponentData, installed_dir), + base::BindOnce(&HandleComponentData, installed_dir, kNTPManifestFile), base::BindOnce(&NTPBackgroundImagesService::OnGetComponentJsonData, weak_factory_.GetWeakPtr())); } @@ -531,7 +522,8 @@ void NTPBackgroundImagesService::OnSponsoredComponentReady( base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock()}, - base::BindOnce(&HandleComponentData, installed_dir), + base::BindOnce(&HandleComponentData, installed_dir, + kNTPSponsoredManifestFile), base::BindOnce( &NTPBackgroundImagesService::OnGetSponsoredComponentJsonData, weak_factory_.GetWeakPtr(), is_super_referral)); @@ -557,6 +549,9 @@ void NTPBackgroundImagesService::OnGetSponsoredComponentJsonData( } else { si_images_data_ = std::make_unique( json_string, si_installed_dir_); + for (auto& observer : observer_list_) { + observer.OnUpdated(json_string); + } } if (is_super_referral && !sr_images_data_->IsValid()) { diff --git a/components/ntp_background_images/browser/ntp_background_images_service.h b/components/ntp_background_images/browser/ntp_background_images_service.h index 360b301ea8a6..4cb89fbbef14 100644 --- a/components/ntp_background_images/browser/ntp_background_images_service.h +++ b/components/ntp_background_images/browser/ntp_background_images_service.h @@ -38,6 +38,7 @@ class NTPBackgroundImagesService { // Called whenever ntp background images component is updated. virtual void OnUpdated(NTPBackgroundImagesData* data) = 0; virtual void OnUpdated(NTPSponsoredImagesData* data) = 0; + virtual void OnUpdated(const std::string& json) {} // Called when SR campaign ended. virtual void OnSuperReferralEnded() = 0; protected: @@ -171,15 +172,15 @@ class NTPBackgroundImagesService { PrefChangeRegistrar pref_change_registrar_; // This is only used for registration during initial(first) SR component // download. After initial download is done, it's cached to - // |kNewTabPageCachedSuperReferralComponentInfo|. At next launch, this cached - // info is used for registering SR component. - // Why component info is temporarily stored to |initial_sr_component_info_| - // when mapping table is fetched instead of directly store it into that prefs? - // The reason is |kNewTabPageCachedSuperReferralComponentInfo| is used to - // check whether initial download is finished or not. Knowing initial download - // is done is important for super referral. If this is SR install, we should - // not show SI images until user chooses Brave default images. So, we should - // know the exact timing whether SR assets is ready to use or not. + // |kNewTabPageCachedSuperReferralComponentInfo|. At next launch, this + // cached info is used for registering SR component. Why component info is + // temporarily stored to |initial_sr_component_info_| when mapping table is + // fetched instead of directly store it into that prefs? The reason is + // |kNewTabPageCachedSuperReferralComponentInfo| is used to check whether + // initial download is finished or not. Knowing initial download is done is + // important for super referral. If this is SR install, we should not show + // SI images until user chooses Brave default images. So, we should know the + // exact timing whether SR assets is ready to use or not. std::optional initial_sr_component_info_; base::WeakPtrFactory weak_factory_; }; diff --git a/components/ntp_background_images/browser/ntp_background_images_service_unittest.cc b/components/ntp_background_images/browser/ntp_background_images_service_unittest.cc index 37838acc4ad5..4c44c92a039d 100644 --- a/components/ntp_background_images/browser/ntp_background_images_service_unittest.cc +++ b/components/ntp_background_images/browser/ntp_background_images_service_unittest.cc @@ -333,14 +333,14 @@ TEST_F(NTPBackgroundImagesServiceTest, InternalDataTest) { EXPECT_EQ(image_count, campaign.backgrounds.size()); EXPECT_EQ(696, campaign.backgrounds[0].focal_point.x()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("background-1.jpg"), - campaign.backgrounds[0].image_file.BaseName()); + campaign.backgrounds[0].wallpaper_file.BaseName()); // Check default value is set if "focalPoint" is missed. EXPECT_EQ(0, campaign.backgrounds[1].focal_point.x()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("background-2.jpg"), - campaign.backgrounds[1].image_file.BaseName()); + campaign.backgrounds[1].wallpaper_file.BaseName()); EXPECT_EQ(0, campaign.backgrounds[2].focal_point.x()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("background-3.jpg"), - campaign.backgrounds[2].image_file.BaseName()); + campaign.backgrounds[2].wallpaper_file.BaseName()); EXPECT_TRUE(campaign.backgrounds[0].creative_instance_id.empty()); EXPECT_FALSE(campaign.backgrounds[1].creative_instance_id.empty()); EXPECT_TRUE(campaign.backgrounds[2].creative_instance_id.empty()); @@ -464,7 +464,7 @@ TEST_F(NTPBackgroundImagesServiceTest, MultipleCampaignsTest) { EXPECT_FALSE(campaign_0.campaign_id.empty()); EXPECT_EQ(3UL, campaign_0.backgrounds.size()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("background-1.jpg"), - campaign_0.backgrounds[0].image_file.BaseName()); + campaign_0.backgrounds[0].wallpaper_file.BaseName()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("logo.png"), campaign_0.backgrounds[0].logo.image_file.BaseName()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("logo-2.png"), @@ -477,15 +477,13 @@ TEST_F(NTPBackgroundImagesServiceTest, MultipleCampaignsTest) { EXPECT_FALSE(campaign_1.campaign_id.empty()); EXPECT_EQ(2UL, campaign_1.backgrounds.size()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("background-4.jpg"), - campaign_1.backgrounds[0].image_file.BaseName()); + campaign_1.backgrounds[0].wallpaper_file.BaseName()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("background-5.jpg"), - campaign_1.backgrounds[1].image_file.BaseName()); + campaign_1.backgrounds[1].wallpaper_file.BaseName()); EXPECT_EQ(base::FilePath::FromUTF8Unsafe("logo-4.png"), campaign_1.backgrounds[1].logo.image_file.BaseName()); EXPECT_FALSE(campaign_1.backgrounds[0].creative_instance_id.empty()); EXPECT_TRUE(campaign_1.backgrounds[1].creative_instance_id.empty()); - - service_->RemoveObserver(&observer); } TEST_F(NTPBackgroundImagesServiceTest, SponsoredImageWithMissingImageUrlTest) { diff --git a/components/ntp_background_images/browser/ntp_sponsored_images_data.cc b/components/ntp_background_images/browser/ntp_sponsored_images_data.cc index b09a824a6f50..f305c7f2cdd8 100644 --- a/components/ntp_background_images/browser/ntp_sponsored_images_data.cc +++ b/components/ntp_background_images/browser/ntp_sponsored_images_data.cc @@ -14,81 +14,43 @@ #include "base/strings/stringprintf.h" #include "base/uuid.h" #include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_info.h" +#include "brave/components/constants/webui_url_constants.h" #include "brave/components/ntp_background_images/browser/url_constants.h" #include "content/public/common/url_constants.h" - -/* Sample photo.json. -{ - "schemaVersion": 1, - "campaignId": "fb7ee174-5430-4fb9-8e97-29bf14e8d828", - "logo": { - "imageUrl": "logo.png", - "alt": "Visit Brave Software", - "companyName": "Brave Software", - "destinationUrl": "https://www.brave.com/" - }, - "wallpapers": [ - { - "imageUrl": "background-1.jpg", - "focalPoint": { - "x": 1468, - "y": 720 - } - }, - { - "imageUrl": "background-2.jpg", - "focalPoint": { - "x": 1650, - "y": 720 - }, - "viewbox": { - "x": 1578, - "y": 1200, - "height": 600, - "width": 800 - }, - "backgroundColor": "#FFFFFF", - "creativeInstanceId": "3e47ee7a-8d2d-445b-8e60-d987fdeea613", - "logo": { - "imageUrl": "logo-2.png", - "alt": "basic attention token", - "companyName": "BAT", - "destinationUrl": "https://basicattentiontoken.org/" - } - } - ] -*/ +#include "ui/gfx/geometry/rect.h" namespace ntp_background_images { namespace { -constexpr int kExpectedSchemaVersion = 1; - -Logo GetLogoFromValue(const base::FilePath& installed_dir, - const std::string& url_prefix, - const base::Value::Dict& value) { - Logo logo; - - if (auto* url = value.FindString(kImageURLKey)) { - logo.image_file = installed_dir.AppendASCII(*url); - logo.image_url = url_prefix + *url; - } - - if (auto* alt_text = value.FindString(kAltKey)) { - logo.alt_text = *alt_text; - } - - if (auto* name = value.FindString(kCompanyNameKey)) { - logo.company_name = *name; - } - - if (auto* url = value.FindString(kDestinationURLKey)) { - logo.destination_url = *url; - } - - return logo; -} +constexpr int kExpectedSchemaVersion = 2; +constexpr int kExpectedCampaignVersion = 1; + +constexpr char kCampaignVersionKey[] = "version"; +constexpr char kCreativeSetsKey[] = "creativeSets"; +constexpr char kCreativeSetIdKey[] = "creativeSetId"; +constexpr char kCreativesKey[] = "creatives"; +constexpr char kCreativeInstanceIdKey[] = "creativeInstanceId"; +constexpr char kCreativeCompanyNameKey[] = "companyName"; +constexpr char kCreativeAltKey[] = "alt"; +constexpr char kCreativeTargetUrlKey[] = "targetUrl"; +constexpr char kCreativeConditionMatchersKey[] = "conditionMatchers"; +constexpr char kCreativeConditionMatcherConditionKey[] = "condition"; +constexpr char kCreativeConditionMatcherPrefPathKey[] = "prefPath"; +constexpr char kWallpaperKey[] = "wallpaper"; +constexpr char kImageWallpaperType[] = "image"; +constexpr char kImageWallpaperRelativeUrlKey[] = "relativeUrl"; +constexpr char kImageWallpaperFocalPointXKey[] = "focalPoint.x"; +constexpr char kImageWallpaperFocalPointYKey[] = "focalPoint.y"; +constexpr char kImageWallpaperViewBoxXKey[] = "viewBox.x"; +constexpr char kImageWallpaperViewBoxYKey[] = "viewBox.y"; +constexpr char kImageWallpaperViewBoxWidthKey[] = "viewBox.width"; +constexpr char kImageWallpaperViewBoxHeightKey[] = "viewBox.height"; +constexpr char kImageWallpaperBackgroundColorKey[] = "backgroundColor"; +constexpr char kImageWallpaperButtonImageRelativeUrlKey[] = + "button.image.relativeUrl"; +constexpr char kRichMediaWallpaperType[] = "richMedia"; +constexpr char kRichMediaWallpaperRelativeUrlKey[] = "relativeUrl"; } // namespace @@ -115,11 +77,11 @@ Logo::~Logo() = default; SponsoredBackground::SponsoredBackground() = default; SponsoredBackground::SponsoredBackground( - const base::FilePath& image_file_path, + const base::FilePath& wallpaper_file_path, const gfx::Point& point, const Logo& test_logo, const std::string& creative_instance_id) - : image_file(image_file_path), + : wallpaper_file(wallpaper_file_path), focal_point(point), creative_instance_id(creative_instance_id), logo(test_logo) {} @@ -147,15 +109,9 @@ NTPSponsoredImagesData::NTPSponsoredImagesData( } base::Value::Dict& root = json_value->GetDict(); - std::optional incomingSchemaVersion = root.FindInt(kSchemaVersionKey); - const bool schemaVersionIsValid = - incomingSchemaVersion && *incomingSchemaVersion == kExpectedSchemaVersion; - if (!schemaVersionIsValid) { - DVLOG(2) << __func__ << "Incoming NTP background images data was not valid." - << " Schema version was " - << (incomingSchemaVersion ? std::to_string(*incomingSchemaVersion) - : "missing") - << ", but we expected " << kExpectedSchemaVersion; + const std::optional schema_version = root.FindInt(kSchemaVersionKey); + if (schema_version != kExpectedSchemaVersion) { + DVLOG(2) << "Mismatched schema version"; return; } @@ -168,24 +124,8 @@ NTPSponsoredImagesData::NTPSponsoredImagesData( url_prefix += kSponsoredImagesPath; } - // SmartNTTs are targeted locally by the browser and are only shown to users - // if the configured conditions match. Non-smart capable browsers that predate - // the introduction of this feature should never show these NTTs. To enforce - // this, the existing `campaigns` array in `photo.json` never includes - // SmartNTTs. A new `campaigns2` array is included in `photo.json`. This - // includes all NTTs, including smart ones. SmartNTT capable browsers read the - // `campaigns2` array, fall back to `campaigns`, and then fall back to the - // root `campaign` for backward compatibility. Non-smart capable browsers - // continue to read the `campaigns` array. - if (auto* campaigns2_value = root.FindList(kCampaigns2Key)) { - ParseCampaignsList(*campaigns2_value, installed_dir); - } else if (auto* campaigns_value = root.FindList(kCampaignsKey)) { + if (auto* campaigns_value = root.FindList(kCampaignsKey)) { ParseCampaignsList(*campaigns_value, installed_dir); - } else { - // Get a global campaign directly if the campaign list doesn't exist. - const auto campaign = GetCampaignFromValue(root, installed_dir); - if (campaign.IsValid()) - campaigns.push_back(campaign); } ParseSRProperties(root, installed_dir); @@ -204,83 +144,231 @@ void NTPSponsoredImagesData::ParseCampaignsList( const base::FilePath& installed_dir) { for (const auto& campaign_value : campaigns_value) { DCHECK(campaign_value.is_dict()); - const auto campaign = + const std::optional campaign = GetCampaignFromValue(campaign_value.GetDict(), installed_dir); - if (campaign.IsValid()) - campaigns.push_back(campaign); + if (!campaign || !campaign->IsValid()) { + DVLOG(2) << "Campaign is not valid. Skipping."; + continue; + } + + campaigns.push_back(*campaign); } } -Campaign NTPSponsoredImagesData::GetCampaignFromValue( +// The changes to RichNTT were made to avoid altering the legacy `Campaign`, +// `SponsoredBackground`, or `Logo` objects, minimizing changes to the +// existing code. The parsing logic will be removed once new tab page ads are +// served from the ads component for both non-Rewards and Rewards. +std::optional NTPSponsoredImagesData::GetCampaignFromValue( const base::Value::Dict& value, const base::FilePath& installed_dir) { Campaign campaign; - if (const std::string* campaign_id = value.FindString(kCampaignIdKey)) { - campaign.campaign_id = *campaign_id; + const std::optional campaign_version = + value.FindInt(kCampaignVersionKey); + if (campaign_version != kExpectedCampaignVersion) { + // Currently, only version 1 is supported. Update this code to maintain + // backwards compatibility when adding new schema versions. + return std::nullopt; } - Logo default_logo; - if (auto* logo = value.FindDict(kLogoKey)) { - default_logo = GetLogoFromValue(installed_dir, url_prefix, *logo); + const std::string* const campaign_id = value.FindString(kCampaignIdKey); + if (!campaign_id) { + // Campaign ID is required. + return std::nullopt; } + campaign.campaign_id = *campaign_id; - if (auto* wallpapers = value.FindList(kWallpapersKey)) { - for (const auto& entry : *wallpapers) { - const auto& wallpaper = entry.GetDict(); - const std::string* image_url = wallpaper.FindString(kImageURLKey); - if (!image_url) { - continue; - } + const base::Value::List* const creative_sets = + value.FindList(kCreativeSetsKey); + if (!creative_sets) { + // Creative sets are required. + return std::nullopt; + } + for (const auto& creative_set : *creative_sets) { + const base::Value::Dict* const creative_set_dict = creative_set.GetIfDict(); + if (!creative_set_dict) { + // Invalid creative set. + return std::nullopt; + } + + const std::string* const creative_set_id = + creative_set_dict->FindString(kCreativeSetIdKey); + if (!creative_set_id) { + // Creative set ID is required. + return std::nullopt; + } + + const base::Value::List* const creatives = + creative_set_dict->FindList(kCreativesKey); + if (!creatives) { + // Creative are required. + return std::nullopt; + } + + for (const auto& creative : *creatives) { SponsoredBackground background; - background.image_file = installed_dir.AppendASCII(*image_url); - if (auto* focal_point = wallpaper.FindDict(kWallpaperFocalPointKey)) { - background.focal_point = {focal_point->FindInt(kXKey).value_or(0), - focal_point->FindInt(kYKey).value_or(0)}; + const base::Value::Dict* const creative_dict = creative.GetIfDict(); + if (!creative_dict) { + // Invalid creative. + return std::nullopt; + } + + const std::string* const creative_instance_id = + creative_dict->FindString(kCreativeInstanceIdKey); + if (!creative_instance_id) { + // Creative instance ID is required. + return std::nullopt; + } + background.creative_instance_id = *creative_instance_id; + + const std::string* const company_name = + creative_dict->FindString(kCreativeCompanyNameKey); + if (!company_name) { + // Company name is required. + return std::nullopt; + } + background.logo.company_name = *company_name; + + const std::string* const alt = creative_dict->FindString(kCreativeAltKey); + if (!alt) { + // Alt is required. + return std::nullopt; } + background.logo.alt_text = *alt; - if (const auto* const condition_matchers = - wallpaper.FindList(kWallpaperConditionMatchersKey)) { + const std::string* const target_url = + creative_dict->FindString(kCreativeTargetUrlKey); + if (!target_url) { + // Target URL is required. + return std::nullopt; + } + background.logo.destination_url = *target_url; + + // Condition matchers. + const base::Value::List* const condition_matchers = + creative_dict->FindList(kCreativeConditionMatchersKey); + if (condition_matchers) { + // Condition matchers are optional. for (const auto& condition_matcher : *condition_matchers) { - const auto& dict = condition_matcher.GetDict(); - const auto* const pref_path = - dict.FindString(kWallpaperConditionMatcherPrefPathKey); - if (!pref_path) { - continue; + const base::Value::Dict* const condition_matcher_dict = + condition_matcher.GetIfDict(); + if (!condition_matcher_dict) { + // Invalid condition matcher. + return std::nullopt; } - const auto* const condition = - dict.FindString(kWallpaperConditionMatcherKey); + const std::string* const condition = + condition_matcher_dict->FindString( + kCreativeConditionMatcherConditionKey); if (!condition) { - continue; + // Condition is required. + return std::nullopt; + } + + const std::string* const pref_path = + condition_matcher_dict->FindString( + kCreativeConditionMatcherPrefPathKey); + if (!pref_path) { + // Pref path is required. + return std::nullopt; } background.condition_matchers.emplace(*pref_path, *condition); } } - if (auto* viewbox = wallpaper.FindDict(kViewboxKey)) { - gfx::Rect rect(viewbox->FindInt(kXKey).value_or(0), - viewbox->FindInt(kYKey).value_or(0), - viewbox->FindInt(kWidthKey).value_or(0), - viewbox->FindInt(kHeightKey).value_or(0)); - background.viewbox.emplace(rect); + // Wallpaper. + const base::Value::Dict* const wallpaper = + creative_dict->FindDict(kWallpaperKey); + if (!wallpaper) { + // Wallpaper is required. + return std::nullopt; } - if (auto* background_color = wallpaper.FindString(kBackgroundColorKey)) { - background.background_color = *background_color; - } - if (auto* creative_instance_id = - wallpaper.FindString(kCreativeInstanceIDKey)) { - background.creative_instance_id = *creative_instance_id; + + const std::string* const wallpaper_type = + wallpaper->FindString(kWallpaperTypeKey); + if (!wallpaper_type) { + // Wallpaper type is required. + return std::nullopt; } - if (auto* wallpaper_logo = wallpaper.FindDict(kLogoKey)) { - background.logo = - GetLogoFromValue(installed_dir, url_prefix, *wallpaper_logo); + + if (*wallpaper_type == kImageWallpaperType) { + // Image. + background.wallpaper_type = WallpaperType::kImage; + + const std::string* const relative_url = + wallpaper->FindString(kImageWallpaperRelativeUrlKey); + if (!relative_url) { + // Relative url is required. + return std::nullopt; + } + background.wallpaper_file = installed_dir.AppendASCII(*relative_url); + background.wallpaper_url = GURL(url_prefix + *relative_url); + + // Focal point (optional). + const int focal_point_x = + wallpaper->FindIntByDottedPath(kImageWallpaperFocalPointXKey) + .value_or(0); + const int focal_point_y = + wallpaper->FindIntByDottedPath(kImageWallpaperFocalPointYKey) + .value_or(0); + background.focal_point = {focal_point_x, focal_point_y}; + + // View box (optional for iOS). + const int view_box_x = + wallpaper->FindIntByDottedPath(kImageWallpaperViewBoxXKey) + .value_or(0); + const int view_box_y = + wallpaper->FindIntByDottedPath(kImageWallpaperViewBoxYKey) + .value_or(0); + const int view_box_width = + wallpaper->FindIntByDottedPath(kImageWallpaperViewBoxWidthKey) + .value_or(0); + const int view_box_height = + wallpaper->FindIntByDottedPath(kImageWallpaperViewBoxHeightKey) + .value_or(0); + background.viewbox = {view_box_x, view_box_y, view_box_width, + view_box_height}; + + // Background color (optional for iOS). + if (const std::string* const background_color = + wallpaper->FindString(kImageWallpaperBackgroundColorKey)) { + background.background_color = *background_color; + } + + // Button. + const std::string* const button_image_relative_url = + wallpaper->FindStringByDottedPath( + kImageWallpaperButtonImageRelativeUrlKey); + if (!button_image_relative_url) { + // Button image relative url is required. + return std::nullopt; + } + background.logo.image_file = + installed_dir.AppendASCII(*button_image_relative_url); + background.logo.image_url = url_prefix + *button_image_relative_url; + } else if (*wallpaper_type == kRichMediaWallpaperType) { + // Rich media. + background.wallpaper_type = WallpaperType::kRichMedia; + + const std::string* const relative_url = + wallpaper->FindStringByDottedPath( + kRichMediaWallpaperRelativeUrlKey); + if (!relative_url) { + // Relative url is required. + return std::nullopt; + } + background.wallpaper_file = installed_dir.AppendASCII(*relative_url); + background.wallpaper_url = + GURL(kNTPSponsoredRichMediaUrl + *relative_url); } else { - background.logo = default_logo; + // Invalid wallpaper type. + return std::nullopt; } + campaign.backgrounds.push_back(background); } } @@ -350,12 +438,27 @@ std::optional NTPSponsoredImagesData::GetBackgroundAt( data.Set(kIsBackgroundKey, false); data.Set(kWallpaperIDKey, base::Uuid::GenerateRandomV4().AsLowercaseString()); - const auto background_file_path = - campaign.backgrounds[background_index].image_file; - const std::string wallpaper_image_url = - url_prefix + background_file_path.BaseName().AsUTF8Unsafe(); + const WallpaperType wallpaper_type = + campaign.backgrounds[background_index].wallpaper_type; + switch (wallpaper_type) { + case WallpaperType::kImage: { + data.Set(kWallpaperTypeKey, "image"); - data.Set(kWallpaperImageURLKey, wallpaper_image_url); + break; + } + + case WallpaperType::kRichMedia: { + data.Set(kWallpaperTypeKey, "richMedia"); + + break; + } + } + + data.Set(kWallpaperImageURLKey, + campaign.backgrounds[background_index].wallpaper_url.spec()); + + const auto background_file_path = + campaign.backgrounds[background_index].wallpaper_file; data.Set(kWallpaperImagePathKey, background_file_path.AsUTF8Unsafe()); data.Set(kWallpaperFocalPointXKey, campaign.backgrounds[background_index].focal_point.x()); @@ -417,16 +520,6 @@ NTPSponsoredImagesData::GetBackgroundFromAdInfo( return std::nullopt; } - if (VLOG_IS_ON(0)) { - if (!AdInfoMatchesSponsoredImage(ad_info, campaign_index, - background_index)) { - VLOG(0) << "Served creative info does not fully match with NTP " - "sponsored images metadata. Campaign id: " - << ad_info.campaign_id - << ". Creative instance id: " << ad_info.creative_instance_id; - } - } - std::optional data = GetBackgroundAt(campaign_index, background_index); if (data) { @@ -450,67 +543,4 @@ void NTPSponsoredImagesData::PrintCampaignsParsingResult() const { } } -bool NTPSponsoredImagesData::AdInfoMatchesSponsoredImage( - const brave_ads::NewTabPageAdInfo& ad_info, - size_t campaign_index, - size_t background_index) const { - DCHECK(campaign_index < campaigns.size() && background_index >= 0 && - background_index < campaigns[campaign_index].backgrounds.size()); - - const Campaign& campaign = campaigns[campaign_index]; - if (!campaign.IsValid()) { - return false; - } - - if (ad_info.campaign_id != campaign.campaign_id) { - return false; - } - - const SponsoredBackground& background = - campaign.backgrounds[background_index]; - if (ad_info.creative_instance_id != background.creative_instance_id) { - return false; - } - - if (ad_info.target_url != GURL(background.logo.destination_url)) { - return false; - } - - const std::string ad_image_filename = ad_info.image_url.ExtractFileName(); - if (ad_image_filename.empty()) { - return false; - } - - if (base::FilePath::FromUTF8Unsafe(ad_image_filename).BaseName() != - background.logo.image_file.BaseName()) { - return false; - } - - if (ad_info.alt != background.logo.alt_text) { - return false; - } - - if (ad_info.company_name != background.logo.company_name) { - return false; - } - - const auto it = base::ranges::find_if( - ad_info.wallpapers, [&background](const auto& wallpaper_info) { - const std::string wallpaper_image_filename = - wallpaper_info.image_url.ExtractFileName(); - if (wallpaper_image_filename.empty()) { - return false; - } - - if (base::FilePath::FromUTF8Unsafe(wallpaper_image_filename) - .BaseName() != background.image_file.BaseName()) { - return false; - } - return wallpaper_info.focal_point.x == background.focal_point.x() && - wallpaper_info.focal_point.y == background.focal_point.y(); - }); - - return it != ad_info.wallpapers.end(); -} - } // namespace ntp_background_images diff --git a/components/ntp_background_images/browser/ntp_sponsored_images_data.h b/components/ntp_background_images/browser/ntp_sponsored_images_data.h index 22b659e8f815..46de5c4399cd 100644 --- a/components/ntp_background_images/browser/ntp_sponsored_images_data.h +++ b/components/ntp_background_images/browser/ntp_sponsored_images_data.h @@ -6,7 +6,6 @@ #ifndef BRAVE_COMPONENTS_NTP_BACKGROUND_IMAGES_BROWSER_NTP_SPONSORED_IMAGES_DATA_H_ #define BRAVE_COMPONENTS_NTP_BACKGROUND_IMAGES_BROWSER_NTP_SPONSORED_IMAGES_DATA_H_ -#include #include #include #include @@ -16,6 +15,7 @@ #include "brave/components/brave_ads/core/public/serving/targeting/condition_matcher/condition_matcher_util.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" +#include "url/gurl.h" namespace brave_ads { struct NewTabPageAdInfo; @@ -55,8 +55,12 @@ struct Logo { ~Logo(); }; +enum WallpaperType { kImage, kRichMedia }; + struct SponsoredBackground { - base::FilePath image_file; + WallpaperType wallpaper_type; + base::FilePath wallpaper_file; + GURL wallpaper_url; gfx::Point focal_point; brave_ads::ConditionMatcherMap condition_matchers; std::string background_color; @@ -68,7 +72,7 @@ struct SponsoredBackground { SponsoredBackground(); // For unit test. - SponsoredBackground(const base::FilePath& image_file_path, + SponsoredBackground(const base::FilePath& wallpaper_file_path, const gfx::Point& point, const Logo& test_logo, const std::string& creative_instance_id); @@ -105,8 +109,9 @@ struct NTPSponsoredImagesData { const base::FilePath& installed_dir); // Parse common properties for SI & SR. - Campaign GetCampaignFromValue(const base::Value::Dict& value, - const base::FilePath& installed_dir); + std::optional GetCampaignFromValue( + const base::Value::Dict& value, + const base::FilePath& installed_dir); void ParseSRProperties(const base::Value::Dict& value, const base::FilePath& installed_dir); @@ -118,10 +123,6 @@ struct NTPSponsoredImagesData { bool IsSuperReferral() const; void PrintCampaignsParsingResult() const; - bool AdInfoMatchesSponsoredImage(const brave_ads::NewTabPageAdInfo& ad_info, - size_t campaign_index, - size_t background_index) const; - std::string url_prefix; std::vector campaigns; diff --git a/components/ntp_background_images/browser/ntp_sponsored_images_source.cc b/components/ntp_background_images/browser/ntp_sponsored_images_source.cc index 8a017631e71a..fcfd7bd4ac4d 100644 --- a/components/ntp_background_images/browser/ntp_sponsored_images_source.cc +++ b/components/ntp_background_images/browser/ntp_sponsored_images_source.cc @@ -7,13 +7,11 @@ #include #include -#include #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/functional/bind.h" #include "base/memory/ref_counted_memory.h" -#include "base/strings/stringprintf.h" #include "base/task/thread_pool.h" #include "brave/components/ntp_background_images/browser/ntp_background_images_service.h" #include "brave/components/ntp_background_images/browser/ntp_sponsored_images_data.h" @@ -128,13 +126,13 @@ base::FilePath NTPSponsoredImagesSource::GetLocalFilePathFor( const auto logo_basename_from_data = background.logo.image_file.BaseName(); const auto wallpaper_basename_from_data = - background.image_file.BaseName(); + background.wallpaper_file.BaseName(); if (logo_basename_from_data == basename_from_path) return background.logo.image_file; if (wallpaper_basename_from_data == basename_from_path) - return background.image_file; + return background.wallpaper_file; } } @@ -162,7 +160,7 @@ bool NTPSponsoredImagesSource::IsValidPath(const std::string& path) const { const auto logo_basename_from_data = background.logo.image_file.BaseName(); const auto wallpaper_basename_from_data = - background.image_file.BaseName(); + background.wallpaper_file.BaseName(); if (logo_basename_from_data == basename_from_path || wallpaper_basename_from_data == basename_from_path) diff --git a/components/ntp_background_images/browser/ntp_sponsored_rich_media_source.cc b/components/ntp_background_images/browser/ntp_sponsored_rich_media_source.cc new file mode 100644 index 000000000000..f524d17e112c --- /dev/null +++ b/components/ntp_background_images/browser/ntp_sponsored_rich_media_source.cc @@ -0,0 +1,153 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/ntp_background_images/browser/ntp_sponsored_rich_media_source.h" + +#include +#include + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/functional/bind.h" +#include "base/memory/ref_counted_memory.h" +#include "base/task/thread_pool.h" +#include "brave/components/constants/webui_url_constants.h" +#include "brave/components/ntp_background_images/browser/ntp_background_images_service.h" +#include "brave/components/ntp_background_images/browser/ntp_sponsored_images_data.h" +#include "brave/components/ntp_background_images/browser/view_counter_service.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "net/base/mime_util.h" +#include "url/gurl.h" + +namespace ntp_background_images { + +namespace { + +std::optional ReadFileToString(const base::FilePath& path) { + std::string contents; + if (!base::ReadFileToString(path, &contents)) { + return std::optional(); + } + return contents; +} + +} // namespace + +NTPSponsoredRichMediaSource::NTPSponsoredRichMediaSource( + NTPBackgroundImagesService* service) + : service_(service), weak_factory_(this) {} + +NTPSponsoredRichMediaSource::~NTPSponsoredRichMediaSource() = default; + +std::string NTPSponsoredRichMediaSource::GetSource() { + return kNTPSponsoredRichMediaUrl; +} + +void NTPSponsoredRichMediaSource::StartDataRequest( + const GURL& url, + const content::WebContents::Getter& wc_getter, + GotDataCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + const std::string path = URLDataSource::URLToRequestPath(url); + const std::optional file_path = + MaybeGetFilePathForDataRequest(path); + if (!file_path) { + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), + scoped_refptr())); + + return; + } + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&ReadFileToString, *file_path), + base::BindOnce(&NTPSponsoredRichMediaSource::ReadFileCallback, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void NTPSponsoredRichMediaSource::ReadFileCallback( + GotDataCallback callback, + std::optional input) { + if (!input) { + return std::move(callback).Run(scoped_refptr()); + } + + std::move(callback).Run( + new base::RefCountedBytes(base::as_byte_span(*input))); +} + +std::string NTPSponsoredRichMediaSource::GetMimeType(const GURL& url) { + std::string mime_type; + std::string file_path_extension = + base::FilePath(url.path_piece()).Extension(); + if (!file_path_extension.empty()) { + net::GetWellKnownMimeTypeFromExtension(file_path_extension.substr(1), + &mime_type); + } + + return mime_type; +} + +bool NTPSponsoredRichMediaSource::AllowCaching() { + return false; +} + +std::string NTPSponsoredRichMediaSource::GetContentSecurityPolicy( + network::mojom::CSPDirectiveName directive) { + switch (directive) { + case network::mojom::CSPDirectiveName::FrameAncestors: + return std::string("frame-ancestors ") + kChromeUINewTabURL + ";"; + case network::mojom::CSPDirectiveName::Sandbox: + return std::string("sandbox allow-scripts;"); + case network::mojom::CSPDirectiveName::DefaultSrc: + return std::string("default-src 'none';"); + case network::mojom::CSPDirectiveName::BaseURI: + return std::string("base-uri 'none';"); + case network::mojom::CSPDirectiveName::FormAction: + return std::string("form-action 'none';"); + case network::mojom::CSPDirectiveName::ScriptSrc: + return std::string("script-src 'self' 'unsafe-inline';"); + case network::mojom::CSPDirectiveName::StyleSrc: + return std::string("style-src 'self';"); + case network::mojom::CSPDirectiveName::ImgSrc: + return std::string("img-src 'self';"); + case network::mojom::CSPDirectiveName::MediaSrc: + return std::string("media-src 'self';"); + default: + return content::URLDataSource::GetContentSecurityPolicy(directive); + } +} + +std::optional +NTPSponsoredRichMediaSource::MaybeGetFilePathForDataRequest( + const std::string& path) { + const NTPSponsoredImagesData* const images_data = + service_->GetBrandedImagesData(false); + if (!images_data) { + return std::nullopt; + } + + const std::string creative_file_path = + base::FilePath::FromUTF8Unsafe(path).DirName().AsUTF8Unsafe(); + + const base::FilePath base_name = + base::FilePath::FromUTF8Unsafe(path).BaseName(); + + for (const auto& campaign : images_data->campaigns) { + for (const auto& creative : campaign.backgrounds) { + // Sandbox the path to the creative file path to prevent path traversal. + if (creative_file_path == creative.creative_instance_id) { + return creative.wallpaper_file.DirName().Append(base_name); + } + } + } + + return std::nullopt; +} + +} // namespace ntp_background_images diff --git a/components/ntp_background_images/browser/ntp_sponsored_rich_media_source.h b/components/ntp_background_images/browser/ntp_sponsored_rich_media_source.h new file mode 100644 index 000000000000..ed004497b5c8 --- /dev/null +++ b/components/ntp_background_images/browser/ntp_sponsored_rich_media_source.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_NTP_BACKGROUND_IMAGES_BROWSER_NTP_SPONSORED_RICH_MEDIA_SOURCE_H_ +#define BRAVE_COMPONENTS_NTP_BACKGROUND_IMAGES_BROWSER_NTP_SPONSORED_RICH_MEDIA_SOURCE_H_ + +#include +#include + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "content/public/browser/url_data_source.h" + +class GURL; + +namespace base { +class FilePath; +} // namespace base + +namespace ntp_background_images { + +class NTPBackgroundImagesService; + +// This serves Rich Media data. +class NTPSponsoredRichMediaSource : public content::URLDataSource { + public: + explicit NTPSponsoredRichMediaSource(NTPBackgroundImagesService* service); + + NTPSponsoredRichMediaSource(const NTPSponsoredRichMediaSource&) = delete; + NTPSponsoredRichMediaSource& operator=(const NTPSponsoredRichMediaSource&) = + delete; + + ~NTPSponsoredRichMediaSource() override; + + private: + // content::URLDataSource: + std::string GetSource() override; + void StartDataRequest(const GURL& url, + const content::WebContents::Getter& wc_getter, + GotDataCallback callback) override; + std::string GetMimeType(const GURL& url) override; + bool AllowCaching() override; + std::string GetContentSecurityPolicy( + network::mojom::CSPDirectiveName directive) override; + + std::optional MaybeGetFilePathForDataRequest( + const std::string& path); + void ReadFileCallback(GotDataCallback callback, + std::optional input); + + raw_ptr service_ = nullptr; // not owned. + base::WeakPtrFactory weak_factory_; +}; + +} // namespace ntp_background_images + +#endif // BRAVE_COMPONENTS_NTP_BACKGROUND_IMAGES_BROWSER_NTP_SPONSORED_RICH_MEDIA_SOURCE_H_ diff --git a/components/ntp_background_images/browser/switches.h b/components/ntp_background_images/browser/switches.h index e7e6771dac6a..c8bff49b5174 100644 --- a/components/ntp_background_images/browser/switches.h +++ b/components/ntp_background_images/browser/switches.h @@ -11,8 +11,8 @@ namespace ntp_background_images { namespace switches { // Allows forcing background images to use a local directory to find the json -// (photo.json for sponsored images or data.json for super referral) rule file -// and associated images. +// (campaigns.json for sponsored images or data.json for super referral) rule +// file and associated images. inline constexpr char kNTPSponsoredImagesDataPathForTesting[] = "ntp-sponsored-images-data-path"; inline constexpr char kNTPSuperReferralDataPathForTesting[] = diff --git a/components/ntp_background_images/browser/url_constants.h b/components/ntp_background_images/browser/url_constants.h index c10fdf89d035..59b1682b0853 100644 --- a/components/ntp_background_images/browser/url_constants.h +++ b/components/ntp_background_images/browser/url_constants.h @@ -26,10 +26,6 @@ inline constexpr char kThemeNameKey[] = "themeName"; inline constexpr char kLogoKey[] = "logo"; -inline constexpr char kCampaignIdKey[] = "campaignId"; - -inline constexpr char kWallpapersKey[] = "wallpapers"; -inline constexpr char kWallpaperFocalPointKey[] = "focalPoint"; inline constexpr char kWallpaperConditionMatchersKey[] = "conditionMatchers"; inline constexpr char kWallpaperConditionMatcherPrefPathKey[] = "prefPath"; inline constexpr char kWallpaperConditionMatcherKey[] = "condition"; @@ -45,13 +41,17 @@ inline constexpr char kTopSiteNameKey[] = "name"; inline constexpr char kTopSiteIconURLKey[] = "iconUrl"; inline constexpr char kImageURLKey[] = "imageUrl"; +inline constexpr char kHtmlURLKey[] = "htmlUrl"; +inline constexpr char kAssetsKey[] = "assets"; inline constexpr char kDestinationURLKey[] = "destinationUrl"; inline constexpr char kBackgroundColorKey[] = "backgroundColor"; inline constexpr char kCompanyNameKey[] = "companyName"; inline constexpr char kViewboxKey[] = "viewbox"; +inline constexpr char kCampaignIdKey[] = "campaignId"; inline constexpr char kCreativeInstanceIDKey[] = "creativeInstanceId"; inline constexpr char kWallpaperIDKey[] = "wallpaperId"; +inline constexpr char kPlacementIDKey[] = "placementId"; inline constexpr char kIsSponsoredKey[] = "isSponsored"; inline constexpr char kWallpaperImageURLKey[] = "wallpaperImageUrl"; diff --git a/components/ntp_background_images/browser/view_counter_service.cc b/components/ntp_background_images/browser/view_counter_service.cc index 8fa944126da8..7f6baef857c3 100644 --- a/components/ntp_background_images/browser/view_counter_service.cc +++ b/components/ntp_background_images/browser/view_counter_service.cc @@ -18,6 +18,7 @@ #include "base/metrics/histogram_macros.h" #include "brave/components/brave_ads/core/browser/service/ads_service.h" #include "brave/components/brave_ads/core/mojom/brave_ads.mojom-shared.h" +#include "brave/components/brave_ads/core/public/ad_units/new_tab_page_ad/new_tab_page_ad_event_type_util.h" #include "brave/components/brave_ads/core/public/prefs/pref_provider.h" #include "brave/components/brave_rewards/common/pref_names.h" #include "brave/components/ntp_background_images/browser/brave_ntp_custom_background_service.h" @@ -145,18 +146,15 @@ void ViewCounterService::BrandedWallpaperWillBeDisplayed( const std::string& wallpaper_id, const std::string& creative_instance_id, const std::string& campaign_id) { - if (ads_service_) { - ads_service_->TriggerNewTabPageAdEvent( - wallpaper_id, creative_instance_id, - brave_ads::mojom::NewTabPageAdEventType::kViewedImpression, - /*intentional*/ base::DoNothing()); - - if (ntp_p3a_helper_) { - // Should only report to P3A if rewards is disabled, as required by spec. - ntp_p3a_helper_->RecordView(creative_instance_id, campaign_id); - } + if (ntp_p3a_helper_) { + // Report P3A viewed impression ad event if Brave Rewards are disabled. + ntp_p3a_helper_->RecordView(creative_instance_id, campaign_id); } + MaybeTriggerNewTabPageAdEvent( + wallpaper_id, creative_instance_id, + brave_ads::mojom::NewTabPageAdEventType::kViewedImpression); + branded_new_tab_count_state_->AddDelta(1); UpdateP3AValues(); } @@ -242,11 +240,6 @@ ViewCounterService::GetCurrentBrandedWallpaper() { std::optional ViewCounterService::GetConditionMatchers(const base::Value::Dict& dict) { - // For non-Rewards users, condition matchers should be included in the - // "photo.json" file under the NTP (New Tab Page) sponsored images component, - // within "campaigns2", falling back to "campaigns", or the root "campaign" - // for backwards compatibility. - const auto* const list = dict.FindList(kWallpaperConditionMatchersKey); if (!list || list->empty()) { return std::nullopt; @@ -377,6 +370,13 @@ void ViewCounterService::OnUpdated(NTPSponsoredImagesData* data) { } } +void ViewCounterService::OnUpdated(const std::string& json) { + if (ads_service_) { + ads_service_->ParseAndSaveCreativeNewTabPageAds( + json, /*intentional*/ base::DoNothing()); + } +} + void ViewCounterService::OnSuperReferralEnded() { // Need to reset model because SI images are shown only for every 4th NTP but // we've shown SR images for every NTP. @@ -442,18 +442,80 @@ void ViewCounterService::BrandedWallpaperLogoClicked( const std::string& creative_instance_id, const std::string& destination_url, const std::string& wallpaper_id) { + if (ntp_p3a_helper_) { + // Report P3A clicked ad event to if Brave Rewards are disabled. + ntp_p3a_helper_->RecordClickAndMaybeLand(creative_instance_id); + } + + MaybeTriggerNewTabPageAdEvent( + wallpaper_id, creative_instance_id, + brave_ads::mojom::NewTabPageAdEventType::kClicked); +} + +void ViewCounterService::MaybeTriggerNewTabPageAdEvent( + const std::string& placement_id, + const std::string& creative_instance_id, + brave_ads::mojom::NewTabPageAdEventType mojoma_ad_event_type) { if (!ads_service_) { + // If `brave_ads::kShouldAlwaysRunBraveAdsServiceFeature` flag is disabled, + // `ads_service_` will be null if the user has not joined Brave Rewards. return; } - ads_service_->TriggerNewTabPageAdEvent( - wallpaper_id, creative_instance_id, - brave_ads::mojom::NewTabPageAdEventType::kClicked, - /*intentional*/ base::DoNothing()); + // If `brave_ads::kShouldAlwaysTriggerBraveNewTabPageAdEventsFeature` flag is + // disabled `AdsService::TriggerNewTabPageAdEvent` will be no-op. + ads_service_->TriggerNewTabPageAdEvent(placement_id, creative_instance_id, + mojoma_ad_event_type, + /*intentional*/ base::DoNothing()); +} - if (ntp_p3a_helper_) { - // Should only report to P3A if ads are disabled, as required by spec. - ntp_p3a_helper_->RecordClickAndMaybeLand(creative_instance_id); +void ViewCounterService::TriggerSponsoredRichMediaAdEvent( + const std::string& placement_id, + const std::string& creative_instance_id, + const std::string& ad_event_type) { + if (!ads_service_) { + return; + } + + const std::optional + mojom_ad_event_type = + brave_ads::ToMojomNewTabPageAdEventType(ad_event_type); + if (!mojom_ad_event_type) { + return; + } + + switch (*mojom_ad_event_type) { + case brave_ads::mojom::NewTabPageAdEventType::kServedImpression: { + // Served impressions are handled by the ads component. + break; + } + + case brave_ads::mojom::NewTabPageAdEventType::kViewedImpression: { + // Viewed impressions are handled in `BrandedWallpaperWillBeDisplayed` + // which is called when a sponsored ad will be displayed. + break; + } + + case brave_ads::mojom::NewTabPageAdEventType::kClicked: { + if (ntp_p3a_helper_) { + // Report P3A clicked ad event if Brave Rewards are disabled. + ntp_p3a_helper_->RecordClickAndMaybeLand(creative_instance_id); + } + + MaybeTriggerNewTabPageAdEvent(placement_id, creative_instance_id, + *mojom_ad_event_type); + + break; + } + + case brave_ads::mojom::NewTabPageAdEventType::kMediaPlay: + case brave_ads::mojom::NewTabPageAdEventType::kMedia25: + case brave_ads::mojom::NewTabPageAdEventType::kMedia100: { + MaybeTriggerNewTabPageAdEvent(placement_id, creative_instance_id, + *mojom_ad_event_type); + + break; + } } } diff --git a/components/ntp_background_images/browser/view_counter_service.h b/components/ntp_background_images/browser/view_counter_service.h index 11cab7147ce6..4a5a854b4f4d 100644 --- a/components/ntp_background_images/browser/view_counter_service.h +++ b/components/ntp_background_images/browser/view_counter_service.h @@ -16,6 +16,7 @@ #include "base/scoped_observation.h" #include "base/timer/wall_clock_timer.h" #include "base/values.h" +#include "brave/components/brave_ads/core/mojom/brave_ads.mojom-forward.h" #include "brave/components/brave_ads/core/public/serving/targeting/condition_matcher/condition_matcher_util.h" #include "brave/components/ntp_background_images/browser/ntp_background_images_service.h" #include "brave/components/ntp_background_images/browser/view_counter_model.h" @@ -80,6 +81,14 @@ class ViewCounterService : public KeyedService, const std::string& destination_url, const std::string& wallpaper_id); + void MaybeTriggerNewTabPageAdEvent( + const std::string& placement_id, + const std::string& creative_instance_id, + brave_ads::mojom::NewTabPageAdEventType mojoma_ad_event_type); + void TriggerSponsoredRichMediaAdEvent(const std::string& placement_id, + const std::string& creative_instance_id, + const std::string& ad_event_type); + std::optional GetNextWallpaperForDisplay(); std::optional GetCurrentWallpaperForDisplay(); std::optional GetCurrentWallpaper() const; @@ -149,6 +158,7 @@ class ViewCounterService : public KeyedService, // NTPBackgroundImagesService::Observer void OnUpdated(NTPBackgroundImagesData* data) override; void OnUpdated(NTPSponsoredImagesData* data) override; + void OnUpdated(const std::string& json) override; void OnSuperReferralEnded() override; void ResetNotificationState(); diff --git a/components/ntp_background_images/browser/view_counter_service_unittest.cc b/components/ntp_background_images/browser/view_counter_service_unittest.cc index 0f767157c16f..67f12b07cf36 100644 --- a/components/ntp_background_images/browser/view_counter_service_unittest.cc +++ b/components/ntp_background_images/browser/view_counter_service_unittest.cc @@ -54,12 +54,9 @@ constexpr char kFirstCreativeInstanceId[] = constexpr char kAltText[] = "Technikke: For music lovers."; constexpr char kCompanyName[] = "Technikke"; constexpr char kLogoImageFile[] = "logo_image.png"; -constexpr char kLogoImageUrl[] = "https://static.bave.com/logos/logo_image.png"; constexpr char kDestinationUrl[] = "https://brave.com"; constexpr char kCreativeInstanceId[] = "c0d61af3-3b85-4af4-a3cc-cf1b3dd40e70"; constexpr char kSponsoredImageFile[] = "wallpaper2.jpg"; -constexpr char kSponsoredImageUrl[] = - "https://static.bave.com/image/wallpaper2.jpg"; constexpr int kSponsoredImageFocalPointX = 5233; constexpr int kSponsoredImageFocalPointY = 3464; @@ -220,13 +217,7 @@ class NTPBackgroundImagesViewCounterTest : public testing::Test { ad_info.creative_instance_id = kCreativeInstanceId; ad_info.company_name = kCompanyName; ad_info.alt = kAltText; - ad_info.image_url = GURL(kLogoImageUrl); ad_info.target_url = GURL(kDestinationUrl); - brave_ads::NewTabPageAdWallpaperInfo wallpaper_info; - wallpaper_info.image_url = GURL(kSponsoredImageUrl); - wallpaper_info.focal_point.x = kSponsoredImageFocalPointX; - wallpaper_info.focal_point.y = kSponsoredImageFocalPointY; - ad_info.wallpapers.push_back(wallpaper_info); return ad_info; } @@ -246,13 +237,6 @@ class NTPBackgroundImagesViewCounterTest : public testing::Test { return view_counter_->GetCurrentWallpaperForDisplay(); } - bool AdInfoMatchesSponsoredImage(const brave_ads::NewTabPageAdInfo& ad_info, - size_t campaign_index, - size_t background_index) { - return service_->si_images_data_->AdInfoMatchesSponsoredImage( - ad_info, campaign_index, background_index); - } - protected: base::test::SingleThreadTaskEnvironment task_environment; TestingPrefServiceSimple local_pref_; @@ -488,7 +472,6 @@ TEST_F(NTPBackgroundImagesViewCounterTest, SponsoredImageAdServed) { InitBackgroundAndSponsoredImageWallpapers(); brave_ads::NewTabPageAdInfo ad_info = CreateNewTabPageAdInfo(); - EXPECT_TRUE(AdInfoMatchesSponsoredImage(ad_info, 0, 1)); prefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); @@ -517,7 +500,6 @@ TEST_F(NTPBackgroundImagesViewCounterTest, WrongSponsoredImageAdServed) { brave_ads::NewTabPageAdInfo ad_info = CreateNewTabPageAdInfo(); ad_info.creative_instance_id = "wrong_creative_instance_id"; - EXPECT_FALSE(AdInfoMatchesSponsoredImage(ad_info, 0, 1)); prefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); diff --git a/components/services/bat_ads/bat_ads_impl.cc b/components/services/bat_ads/bat_ads_impl.cc index 9b776b1b483a..e1ccd6b6d9c7 100644 --- a/components/services/bat_ads/bat_ads_impl.cc +++ b/components/services/bat_ads/bat_ads_impl.cc @@ -128,6 +128,12 @@ void BatAdsImpl::TriggerNotificationAdEvent( std::move(callback)); } +void BatAdsImpl::ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) { + GetAds()->ParseAndSaveCreativeNewTabPageAds(json, std::move(callback)); +} + void BatAdsImpl::MaybeServeNewTabPageAd( MaybeServeNewTabPageAdCallback callback) { GetAds()->MaybeServeNewTabPageAd(base::BindOnce( diff --git a/components/services/bat_ads/bat_ads_impl.h b/components/services/bat_ads/bat_ads_impl.h index 502d27f25113..cb9b2b35f068 100644 --- a/components/services/bat_ads/bat_ads_impl.h +++ b/components/services/bat_ads/bat_ads_impl.h @@ -67,6 +67,9 @@ class BatAdsImpl : public mojom::BatAds { brave_ads::mojom::InlineContentAdEventType mojom_ad_event_type, TriggerInlineContentAdEventCallback callback) override; + void ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) override; void MaybeServeNewTabPageAd(MaybeServeNewTabPageAdCallback callback) override; void TriggerNewTabPageAdEvent( const std::string& placement_id, diff --git a/components/services/bat_ads/public/interfaces/bat_ads.mojom b/components/services/bat_ads/public/interfaces/bat_ads.mojom index 38503e4829c5..9e33eb0a0809 100644 --- a/components/services/bat_ads/public/interfaces/bat_ads.mojom +++ b/components/services/bat_ads/public/interfaces/bat_ads.mojom @@ -166,6 +166,7 @@ interface BatAds { brave_ads.mojom.InlineContentAdEventType mojom_ad_event_type) => (bool success); + ParseAndSaveCreativeNewTabPageAds(string json) => (bool success); MaybeServeNewTabPageAd() => (mojo_base.mojom.DictionaryValue? value); TriggerNewTabPageAdEvent( string placement_id, diff --git a/ios/brave-ios/Sources/Brave/Frontend/Browser/New Tab Page/Backgrounds/NewTabPageBackgroundButtonsView.swift b/ios/brave-ios/Sources/Brave/Frontend/Browser/New Tab Page/Backgrounds/NewTabPageBackgroundButtonsView.swift index a6425f30e38f..46f4cf2be0e2 100644 --- a/ios/brave-ios/Sources/Brave/Frontend/Browser/New Tab Page/Backgrounds/NewTabPageBackgroundButtonsView.swift +++ b/ios/brave-ios/Sources/Brave/Frontend/Browser/New Tab Page/Backgrounds/NewTabPageBackgroundButtonsView.swift @@ -22,7 +22,7 @@ class NewTabPageBackgroundButtonsView: UIView, PreferencesObserver { /// Displays the image credit button showing credit to some `name` case imageCredit(_ name: String) /// Displays a brands logo button - case brandLogo(_ logo: NTPSponsoredImageLogo) + case brandLogo(_ logoImagePath: URL) /// Displays a button with a little QR code image case qrCode } @@ -41,8 +41,8 @@ class NewTabPageBackgroundButtonsView: UIView, PreferencesObserver { case .imageCredit(let name): imageCreditButton.label.text = String(format: Strings.photoBy, name) activeView = imageCreditButton - case .brandLogo(let logo): - sponsorLogoButton.imageView.image = UIImage(contentsOfFile: logo.imagePath.path) + case .brandLogo(let logoImagePath): + sponsorLogoButton.imageView.image = UIImage(contentsOfFile: logoImagePath.path) activeView = sponsorLogoButton case .qrCode: activeView = qrCodeButton diff --git a/ios/brave-ios/Sources/Brave/Frontend/Browser/New Tab Page/NewTabPageViewController.swift b/ios/brave-ios/Sources/Brave/Frontend/Browser/New Tab Page/NewTabPageViewController.swift index e80ec2cf0143..bfd4995c486f 100644 --- a/ios/brave-ios/Sources/Brave/Frontend/Browser/New Tab Page/NewTabPageViewController.swift +++ b/ios/brave-ios/Sources/Brave/Frontend/Browser/New Tab Page/NewTabPageViewController.swift @@ -562,8 +562,10 @@ class NewTabPageViewController: UIViewController { videoAdPlayer?.didFinishAutoplayEvent = { [weak self] in guard let self = self else { return } self.backgroundButtonsView.videoAutoplayFinished() - if case .sponsoredMedia(let background) = self.background.currentBackground { - self.backgroundButtonsView.activeButton = .brandLogo(background.logo) + if case .sponsoredMedia(let background) = self.background.currentBackground, + let logoImagePath = background.logo.imagePath + { + self.backgroundButtonsView.activeButton = .brandLogo(logoImagePath) } self.backgroundButtonsView.alpha = 0 UIView.animate( @@ -619,7 +621,9 @@ class NewTabPageViewController: UIViewController { backgroundButtonsView.activeButton = .none } case .sponsoredMedia(let background): - backgroundButtonsView.activeButton = .brandLogo(background.logo) + if let logoImagePath = background.logo.imagePath { + backgroundButtonsView.activeButton = .brandLogo(logoImagePath) + } case .superReferral: backgroundButtonsView.activeButton = .qrCode } diff --git a/ios/browser/api/ads/brave_ads.h b/ios/browser/api/ads/brave_ads.h index 57ba65af4be5..cf77c6ca7945 100644 --- a/ios/browser/api/ads/brave_ads.h +++ b/ios/browser/api/ads/brave_ads.h @@ -113,7 +113,7 @@ OBJC_EXPORT eventType:(BraveAdsInlineContentAdEventType)eventType completion:(void (^)(BOOL success))completion; -- (void)triggerNewTabPageAdEvent:(NSString*)wallpaperId +- (void)triggerNewTabPageAdEvent:(NSString*)placementId creativeInstanceId:(NSString*)creativeInstanceId eventType:(BraveAdsNewTabPageAdEventType)eventType completion:(void (^)(BOOL success))completion; diff --git a/ios/browser/api/ads/brave_ads.mm b/ios/browser/api/ads/brave_ads.mm index 02a105875a02..f1733d94de0e 100644 --- a/ios/browser/api/ads/brave_ads.mm +++ b/ios/browser/api/ads/brave_ads.mm @@ -1516,7 +1516,7 @@ - (void)triggerInlineContentAdEvent:(NSString*)placementId // TODO(https://github.com/brave/brave-browser/issues/33470): Unify Brave Ads // new tab page ad serving. -- (void)triggerNewTabPageAdEvent:(NSString*)wallpaperId +- (void)triggerNewTabPageAdEvent:(NSString*)placementId creativeInstanceId:(NSString*)creativeInstanceId eventType:(BraveAdsNewTabPageAdEventType)eventType completion:(void (^)(BOOL success))completion { @@ -1525,7 +1525,7 @@ - (void)triggerNewTabPageAdEvent:(NSString*)wallpaperId } adsService->TriggerNewTabPageAdEvent( - base::SysNSStringToUTF8(wallpaperId), + base::SysNSStringToUTF8(placementId), base::SysNSStringToUTF8(creativeInstanceId), static_cast(eventType), base::BindOnce(completion)); diff --git a/ios/browser/api/ntp_background_images/ntp_sponsored_image.h b/ios/browser/api/ntp_background_images/ntp_sponsored_image.h index c8563f18dce1..9a0ded9bad18 100644 --- a/ios/browser/api/ntp_background_images/ntp_sponsored_image.h +++ b/ios/browser/api/ntp_background_images/ntp_sponsored_image.h @@ -58,7 +58,7 @@ OBJC_EXPORT OBJC_EXPORT @interface NTPSponsoredImageLogo : NSObject -@property(readonly) NSURL* imagePath; +@property(readonly, nullable) NSURL* imagePath; @property(readonly) NSString* altText; @property(readonly, nullable) NSURL* destinationURL; @property(readonly) NSString* companyName; diff --git a/ios/browser/api/ntp_background_images/ntp_sponsored_image.mm b/ios/browser/api/ntp_background_images/ntp_sponsored_image.mm index 319a20de4108..229a2aeee834 100644 --- a/ios/browser/api/ntp_background_images/ntp_sponsored_image.mm +++ b/ios/browser/api/ntp_background_images/ntp_sponsored_image.mm @@ -127,7 +127,7 @@ - (instancetype)initWithSponsoredBackground: (const ntp_background_images::SponsoredBackground&)sponsoredBackground { auto imagePath = [NSURL fileURLWithPath:base::SysUTF8ToNSString( - sponsoredBackground.image_file.value())]; + sponsoredBackground.wallpaper_file.value())]; auto focalPoint = sponsoredBackground.focal_point.ToCGPoint(); auto backgroundColor = base::SysUTF8ToNSString(sponsoredBackground.background_color); @@ -147,7 +147,7 @@ - (instancetype)initWithSponsoredBackground: @end @interface NTPSponsoredImageLogo () -@property(nonatomic, copy) NSURL* imagePath; +@property(nonatomic, copy, nullable) NSURL* imagePath; @property(nonatomic, copy) NSString* altText; @property(nonatomic, copy, nullable) NSURL* destinationURL; @property(nonatomic, copy) NSString* companyName; diff --git a/ios/browser/brave_ads/ads_service_impl_ios.h b/ios/browser/brave_ads/ads_service_impl_ios.h index 14e16d4e1b45..17c78dd5ccb4 100644 --- a/ios/browser/brave_ads/ads_service_impl_ios.h +++ b/ios/browser/brave_ads/ads_service_impl_ios.h @@ -92,6 +92,9 @@ class AdsServiceImplIOS : public AdsService { void OnFailedToPrefetchNewTabPageAd( const std::string& placement_id, const std::string& creative_instance_id) override; + void ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) override; void TriggerNewTabPageAdEvent( const std::string& placement_id, const std::string& creative_instance_id, diff --git a/ios/browser/brave_ads/ads_service_impl_ios.mm b/ios/browser/brave_ads/ads_service_impl_ios.mm index 17e45cfd24ce..a07cefb88f18 100644 --- a/ios/browser/brave_ads/ads_service_impl_ios.mm +++ b/ios/browser/brave_ads/ads_service_impl_ios.mm @@ -8,6 +8,7 @@ #include #include #include +#include #include "base/check.h" #include "base/files/file_path.h" @@ -216,6 +217,16 @@ NOTIMPLEMENTED() << "Not used on iOS."; } +void AdsServiceImplIOS::ParseAndSaveCreativeNewTabPageAds( + const std::string& json, + ParseAndSaveCreativeNewTabPageAdsCallback callback) { + if (!IsInitialized()) { + return std::move(callback).Run(/*success*/ false); + } + + ads_->ParseAndSaveCreativeNewTabPageAds(json, std::move(callback)); +} + void AdsServiceImplIOS::TriggerNewTabPageAdEvent( const std::string& placement_id, const std::string& creative_instance_id,