From f55fa9140897594cec0eb08fc8dd699322f70544 Mon Sep 17 00:00:00 2001 From: Albert Wang Date: Thu, 17 Sep 2020 11:06:51 -0700 Subject: [PATCH] Support day-parting for Brave Ads --- components/brave_ads/test/BUILD.gn | 1 + vendor/bat-native-ads/BUILD.gn | 6 +- vendor/bat-native-ads/src/bat/ads/database.cc | 1 + .../src/bat/ads/internal/ads_impl.cc | 7 + .../src/bat/ads/internal/bundle/bundle.cc | 28 ++ .../src/bat/ads/internal/bundle/bundle.h | 3 + .../ads/internal/bundle/creative_ad_info.h | 2 + .../internal/bundle/creative_daypart_info.h | 28 ++ .../internal/catalog/catalog_campaign_info.h | 4 +- .../internal/catalog/catalog_day_part_info.h | 24 -- .../internal/catalog/catalog_daypart_info.h | 27 ++ .../bat/ads/internal/catalog/catalog_state.cc | 17 +- .../internal/database/database_migration.cc | 4 + .../ads/internal/database/database_version.cc | 4 +- ...reative_ad_notifications_database_table.cc | 32 +- ...creative_ad_notifications_database_table.h | 2 + ...d_notifications_database_table_unittest.cc | 26 ++ ...reative_new_tab_page_ads_database_table.cc | 44 ++- ...creative_new_tab_page_ads_database_table.h | 2 + ...ew_tab_page_ads_database_table_unittest.cc | 30 ++ .../tables/dayparts_database_table.cc | 167 ++++++++++ .../database/tables/dayparts_database_table.h | 65 ++++ .../exclusion_rules/daypart_frequency_cap.cc | 100 ++++++ .../exclusion_rules/daypart_frequency_cap.h | 58 ++++ .../daypart_frequency_cap_unittest.cc | 296 ++++++++++++++++++ 25 files changed, 933 insertions(+), 45 deletions(-) create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.h delete mode 100644 vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_day_part_info.h create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_daypart_info.h create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/database/tables/dayparts_database_table.cc create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/database/tables/dayparts_database_table.h create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.cc create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h create mode 100644 vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap_unittest.cc diff --git a/components/brave_ads/test/BUILD.gn b/components/brave_ads/test/BUILD.gn index 1ae572c0fbad..d066a188fd2b 100644 --- a/components/brave_ads/test/BUILD.gn +++ b/components/brave_ads/test/BUILD.gn @@ -31,6 +31,7 @@ source_set("brave_ads_unit_tests") { "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/ad_exclusion_rules/new_tab_page_ad_wallpaper_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/landed_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/marked_as_inappropriate_frequency_cap_unittest.cc", diff --git a/vendor/bat-native-ads/BUILD.gn b/vendor/bat-native-ads/BUILD.gn index d3ee4b28d60d..37daa7214187 100644 --- a/vendor/bat-native-ads/BUILD.gn +++ b/vendor/bat-native-ads/BUILD.gn @@ -153,7 +153,7 @@ source_set("ads") { "src/bat/ads/internal/catalog/catalog_creative_new_tab_page_ad_info.h", "src/bat/ads/internal/catalog/catalog_creative_set_info.cc", "src/bat/ads/internal/catalog/catalog_creative_set_info.h", - "src/bat/ads/internal/catalog/catalog_day_part_info.h", + "src/bat/ads/internal/catalog/catalog_daypart_info.h", "src/bat/ads/internal/catalog/catalog_geo_target_info.h", "src/bat/ads/internal/catalog/catalog_issuer_info.cc", "src/bat/ads/internal/catalog/catalog_issuer_info.h", @@ -234,6 +234,8 @@ source_set("ads") { "src/bat/ads/internal/database/tables/creative_ads_database_table.h", "src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.cc", "src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.h", + "src/bat/ads/internal/database/tables/dayparts_database_table.cc", + "src/bat/ads/internal/database/tables/dayparts_database_table.h", "src/bat/ads/internal/database/tables/geo_targets_database_table.cc", "src/bat/ads/internal/database/tables/geo_targets_database_table.h", "src/bat/ads/internal/eligible_ads/eligible_ads_filter.h", @@ -259,6 +261,8 @@ source_set("ads") { "src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap.h", "src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap.cc", "src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap.h", + "src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.cc", + "src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h", "src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap.cc", "src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap.h", "src/bat/ads/internal/frequency_capping/exclusion_rules/exclusion_rule.h", diff --git a/vendor/bat-native-ads/src/bat/ads/database.cc b/vendor/bat-native-ads/src/bat/ads/database.cc index 81407379f6ec..f931676c36cf 100644 --- a/vendor/bat-native-ads/src/bat/ads/database.cc +++ b/vendor/bat-native-ads/src/bat/ads/database.cc @@ -5,6 +5,7 @@ #include "bat/ads/database.h" +#include #include #include diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc b/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc index 43fe4bc70e72..dd0c977b8bf8 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc @@ -33,6 +33,7 @@ #include "bat/ads/internal/filters/ads_history_filter_factory.h" #include "bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap.h" #include "bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap.h" +#include "bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h" #include "bat/ads/internal/frequency_capping/exclusion_rules/exclusion_rule.h" #include "bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap.h" #include "bat/ads/internal/frequency_capping/exclusion_rules/landed_frequency_cap.h" @@ -947,6 +948,10 @@ AdsImpl::CreateAdNotificationExclusionRules() const { std::make_unique(this); exclusion_rules.push_back(std::move(subdivision_targeting_frequency_cap)); + std::unique_ptr daypart_frequency_cap = + std::make_unique(this); + exclusion_rules.push_back(std::move(daypart_frequency_cap)); + std::unique_ptr dismissed_frequency_cap = std::make_unique(this); exclusion_rules.push_back(std::move(dismissed_frequency_cap)); @@ -1268,6 +1273,7 @@ void AdsImpl::DeliverAdNotification() { void AdsImpl::MaybeServeAdNotification( const bool should_serve) { + /* auto ok = ads_client_->ShouldShowNotifications(); auto previous = client_->GetAvailable(); @@ -1310,6 +1316,7 @@ void AdsImpl::MaybeServeAdNotification( return; } + */ ServeAdNotificationIfReady(); } diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle.cc b/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle.cc index b9d2b7b2277a..b6a59cf5a4b8 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle.cc @@ -58,6 +58,7 @@ bool Bundle::UpdateFromCatalog( DeleteCampaigns(); DeleteCategories(); DeleteCreativeAds(); + DeleteDayparts(); DeleteGeoTargets(); SaveCreativeAdNotifications(bundle_state->creative_ad_notifications); @@ -106,6 +107,11 @@ void Bundle::DeleteCreativeAds() { database_table.Delete(std::bind(&Bundle::OnCreativeAdsDeleted, this, _1)); } +void Bundle::DeleteDayparts() { + database::table::Dayparts database_table(ads_); + database_table.Delete(std::bind(&Bundle::OnDaypartsDeleted, this, _1)); +} + void Bundle::DeleteGeoTargets() { database::table::GeoTargets database_table(ads_); database_table.Delete(std::bind(&Bundle::OnGeoTargetsDeleted, this, _1)); @@ -183,6 +189,16 @@ std::unique_ptr Bundle::GenerateFromCatalog( geo_targets.push_back(code); } + std::vector creative_dayparts; + for (const auto& daypart : campaign.dayparts) { + CreativeDaypartInfo creative_daypart_info; + creative_daypart_info.dow = daypart.dow; + creative_daypart_info.start_minute = daypart.start_minute; + creative_daypart_info.end_minute = daypart.start_minute; + + creative_dayparts.push_back(creative_daypart_info); + } + // Creative Sets for (const auto& creative_set : campaign.creative_sets) { uint64_t entries = 0; @@ -236,6 +252,7 @@ std::unique_ptr Bundle::GenerateFromCatalog( creative_set.ad_conversions.size() != 0 ? true : false; info.per_day = creative_set.per_day; info.total_max = creative_set.total_max; + info.dayparts = creative_dayparts; info.geo_targets = geo_targets; info.title = creative.payload.title; info.body = creative.payload.body; @@ -318,6 +335,7 @@ std::unique_ptr Bundle::GenerateFromCatalog( creative_set.ad_conversions.size() != 0 ? true : false; info.per_day = creative_set.per_day; info.total_max = creative_set.total_max; + info.dayparts = creative_dayparts; info.geo_targets = geo_targets; info.company_name = creative.payload.company_name; info.alt = creative.payload.alt; @@ -446,6 +464,16 @@ void Bundle::OnCreativeAdsDeleted( BLOG(3, "Successfully deleted creative ads"); } +void Bundle::OnDaypartsDeleted( + const Result result) { + if (result != SUCCESS) { + BLOG(0, "Failed to delete dayparts"); + return; + } + + BLOG(3, "Successfully deleted dayparts"); +} + void Bundle::OnGeoTargetsDeleted( const Result result) { if (result != SUCCESS) { diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle.h index 3cf90e0dd468..b9acc3c3083b 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle.h @@ -40,6 +40,7 @@ class Bundle { void DeleteCampaigns(); void DeleteCategories(); void DeleteCreativeAds(); + void DeleteDayparts(); void DeleteGeoTargets(); void SaveCreativeAdNotifications( @@ -71,6 +72,8 @@ class Bundle { const Result result); void OnCreativeAdsDeleted( const Result result); + void OnDaypartsDeleted( + const Result result); void OnGeoTargetsDeleted( const Result result); void OnCreativeAdNotificationsSaved( diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.h index f248b3341fd3..9a14ed2e9139 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.h @@ -10,6 +10,7 @@ #include #include +#include "bat/ads/internal/bundle/creative_daypart_info.h" namespace ads { @@ -34,6 +35,7 @@ struct CreativeAdInfo { std::string category; std::vector geo_targets; std::string target_url; + std::vector dayparts; }; using CreativeAdList = std::vector; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.h new file mode 100644 index 000000000000..a64a2f7186b6 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ + +#ifndef BAT_ADS_INTERNAL_BUNDLE_CREATIVE_DAYPART_INFO_H_ +#define BAT_ADS_INTERNAL_BUNDLE_CREATIVE_DAYPART_INFO_H_ + +#include +#include + +#include "bat/ads/internal/time_util.h" + +namespace ads { + +struct CreativeDaypartInfo { + std::string dow = "0123456"; + int start_minute = 0; + int end_minute = + (base::Time::kMinutesPerHour * base::Time::kHoursPerDay) - 1; +}; + +using CreativeDaypartList = std::vector; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_CATALOG_CATALOG_DAYPART_INFO_H_ + diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_campaign_info.h b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_campaign_info.h index 3b4f5ef25ba8..19e259e18d55 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_campaign_info.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_campaign_info.h @@ -10,7 +10,7 @@ #include #include "bat/ads/internal/catalog/catalog_creative_set_info.h" -#include "bat/ads/internal/catalog/catalog_day_part_info.h" +#include "bat/ads/internal/catalog/catalog_daypart_info.h" #include "bat/ads/internal/catalog/catalog_geo_target_info.h" namespace ads { @@ -30,7 +30,7 @@ struct CatalogCampaignInfo { unsigned int daily_cap = 0; std::string advertiser_id; CatalogCreativeSetList creative_sets; - CatalogDayPartList day_parts; + CatalogDaypartList dayparts; CatalogGeoTargetList geo_targets; }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_day_part_info.h b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_day_part_info.h deleted file mode 100644 index 5f469fa36f3d..000000000000 --- a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_day_part_info.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ - -#ifndef BAT_ADS_INTERNAL_CATALOG_CATALOG_DAY_PART_INFO_H_ -#define BAT_ADS_INTERNAL_CATALOG_CATALOG_DAY_PART_INFO_H_ - -#include -#include - -namespace ads { - -struct CatalogDayPartInfo { - std::string dow; - unsigned int start_minute; - unsigned int end_minute; -}; - -using CatalogDayPartList = std::vector; - -} // namespace ads - -#endif // BAT_ADS_INTERNAL_CATALOG_CATALOG_DAY_PART_INFO_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_daypart_info.h b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_daypart_info.h new file mode 100644 index 000000000000..4a33a47f9c33 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_daypart_info.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2019 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 http://mozilla.org/MPL/2.0/. */ + +#ifndef BAT_ADS_INTERNAL_CATALOG_CATALOG_DAYPART_INFO_H_ +#define BAT_ADS_INTERNAL_CATALOG_CATALOG_DAYPART_INFO_H_ + +#include +#include + +#include "bat/ads/internal/time_util.h" + +namespace ads { + +struct CatalogDaypartInfo { + std::string dow = "0123456"; + int start_minute = 0; + int end_minute = + (base::Time::kMinutesPerHour * base::Time::kHoursPerDay) - 1; +}; + +using CatalogDaypartList = std::vector; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_CATALOG_CATALOG_DAYPART_INFO_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_state.cc b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_state.cc index 1d475dd163bd..d6e1a11c9821 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_state.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_state.cc @@ -72,14 +72,19 @@ Result CatalogState::FromJson( } // Day parts - for (const auto& day_part : campaign["dayParts"].GetArray()) { - CatalogDayPartInfo day_part_info; + for (const auto& daypart : campaign["dayParts"].GetArray()) { + CatalogDaypartInfo daypart_info; - day_part_info.dow = day_part["dow"].GetString(); - day_part_info.start_minute = day_part["startMinute"].GetUint(); - day_part_info.end_minute = day_part["endMinute"].GetUint(); + daypart_info.dow = daypart["dow"].GetString(); + daypart_info.start_minute = daypart["startMinute"].GetUint(); + daypart_info.end_minute = daypart["endMinute"].GetUint(); - campaign_info.day_parts.push_back(day_part_info); + campaign_info.dayparts.push_back(daypart_info); + } + + if (campaign_info.dayparts.empty()) { + CatalogDaypartInfo daypart_info; + campaign_info.dayparts.push_back(daypart_info); } // Creative sets diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration.cc index e96015fcd85f..804c21896e0f 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration.cc @@ -17,6 +17,7 @@ #include "bat/ads/internal/database/tables/creative_ad_notifications_database_table.h" #include "bat/ads/internal/database/tables/creative_ads_database_table.h" #include "bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.h" +#include "bat/ads/internal/database/tables/dayparts_database_table.h" #include "bat/ads/internal/database/tables/geo_targets_database_table.h" #include "bat/ads/internal/logging.h" @@ -86,6 +87,9 @@ void Migration::ToVersion( table::GeoTargets geo_targets_database_table(ads_); geo_targets_database_table.Migrate(transaction, to_version); + + table::Dayparts dayparts_database_table(ads_); + dayparts_database_table.Migrate(transaction, to_version); } } // namespace database diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/database_version.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/database_version.cc index bbf0d6863260..ec72c5ee641b 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/database_version.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/database_version.cc @@ -9,11 +9,11 @@ namespace ads { namespace database { int32_t version() { - return 3; + return 4; } int32_t compatible_version() { - return 3; + return 4; } } // namespace database diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table.cc index 779699abdac7..f2c07b8fedf2 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table.cc @@ -40,6 +40,7 @@ CreativeAdNotifications::CreativeAdNotifications( campaigns_database_table_(std::make_unique(ads_)), categories_database_table_(std::make_unique(ads_)), creative_ads_database_table_(std::make_unique(ads_)), + dayparts_database_table_(std::make_unique(ads_)), geo_targets_database_table_(std::make_unique(ads_)) { DCHECK(ads_); } @@ -69,6 +70,7 @@ void CreativeAdNotifications::Save( transaction.get(), creative_ads); creative_ads_database_table_->InsertOrUpdate( transaction.get(), creative_ads); + dayparts_database_table_->InsertOrUpdate(transaction.get(), creative_ads); geo_targets_database_table_->InsertOrUpdate( transaction.get(), creative_ads); } @@ -113,7 +115,10 @@ void CreativeAdNotifications::GetForCategories( "ca.target_url, " "can.title, " "can.body, " - "cam.ptr " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " "FROM %s AS can " "INNER JOIN campaigns AS cam " "ON cam.campaign_id = can.campaign_id " @@ -123,6 +128,8 @@ void CreativeAdNotifications::GetForCategories( "ON ca.creative_set_id = can.creative_set_id " "INNER JOIN geo_targets AS gt " "ON gt.campaign_id = can.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = can.campaign_id " "WHERE c.category IN %s " "AND %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", get_table_name().c_str(), @@ -156,7 +163,10 @@ void CreativeAdNotifications::GetForCategories( DBCommand::RecordBindingType::STRING_TYPE, // target_url DBCommand::RecordBindingType::STRING_TYPE, // title DBCommand::RecordBindingType::STRING_TYPE, // body - DBCommand::RecordBindingType::DOUBLE_TYPE // ptr + DBCommand::RecordBindingType::DOUBLE_TYPE, // ptr + DBCommand::RecordBindingType::STRING_TYPE, // dayparts->dow + DBCommand::RecordBindingType::INT_TYPE, // dayparts->start_minute + DBCommand::RecordBindingType::INT_TYPE // dayparts->end_minute }; DBTransactionPtr transaction = DBTransaction::New(); @@ -187,7 +197,10 @@ void CreativeAdNotifications::GetAll( "ca.target_url, " "can.title, " "can.body, " - "cam.ptr " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " "FROM %s AS can " "INNER JOIN campaigns AS cam " "ON cam.campaign_id = can.campaign_id " @@ -197,6 +210,8 @@ void CreativeAdNotifications::GetAll( "ON ca.creative_set_id = can.creative_set_id " "INNER JOIN geo_targets AS gt " "ON gt.campaign_id = can.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = can.campaign_id " "WHERE %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", get_table_name().c_str(), NowAsString().c_str()); @@ -222,7 +237,10 @@ void CreativeAdNotifications::GetAll( DBCommand::RecordBindingType::STRING_TYPE, // target_url DBCommand::RecordBindingType::STRING_TYPE, // title DBCommand::RecordBindingType::STRING_TYPE, // body - DBCommand::RecordBindingType::DOUBLE_TYPE // ptr + DBCommand::RecordBindingType::DOUBLE_TYPE, // ptr + DBCommand::RecordBindingType::STRING_TYPE, // dayparts->dow + DBCommand::RecordBindingType::INT_TYPE, // dayparts->start_minute + DBCommand::RecordBindingType::INT_TYPE // dayparts->end_minute }; DBTransactionPtr transaction = DBTransaction::New(); @@ -400,6 +418,12 @@ CreativeAdNotificationInfo CreativeAdNotifications::GetFromRecord( creative_ad_notification.body = ColumnString(record, 15); creative_ad_notification.ptr = ColumnDouble(record, 16); + CreativeDaypartInfo daypart; + daypart.dow = ColumnString(record, 17); + daypart.start_minute = ColumnInt(record, 18); + daypart.end_minute = ColumnInt(record, 19); + creative_ad_notification.dayparts.push_back(daypart); + return creative_ad_notification; } diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table.h index ed07f2c7d4e4..adc21ab56307 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table.h @@ -17,6 +17,7 @@ #include "bat/ads/internal/database/tables/campaigns_database_table.h" #include "bat/ads/internal/database/tables/categories_database_table.h" #include "bat/ads/internal/database/tables/creative_ads_database_table.h" +#include "bat/ads/internal/database/tables/dayparts_database_table.h" #include "bat/ads/internal/database/tables/geo_targets_database_table.h" #include "bat/ads/mojom.h" #include "bat/ads/result.h" @@ -106,6 +107,7 @@ class CreativeAdNotifications : public Table { std::unique_ptr campaigns_database_table_; std::unique_ptr categories_database_table_; std::unique_ptr creative_ads_database_table_; + std::unique_ptr dayparts_database_table_; std::unique_ptr geo_targets_database_table_; }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc index 6cd3c7a4aa59..5afd8a9baae4 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc @@ -127,6 +127,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -139,6 +140,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.title = "Test Ad 1 Title"; @@ -158,6 +160,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Technology & Computing-Software"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.title = "Test Ad 2 Title"; @@ -196,6 +199,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -208,6 +212,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.title = "Test Ad 1 Title"; @@ -227,6 +232,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Technology & Computing-Software"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.title = "Test Ad 2 Title"; @@ -246,6 +252,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_3.per_day = 3; info_3.total_max = 4; info_3.category = "Technology & Computing-Software"; + info_3.dayparts.push_back(daypart_info); info_3.geo_targets = { "US" }; info_3.target_url = "https://brave.com"; info_3.title = "Test Ad 3 Title"; @@ -282,6 +289,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info; info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -294,6 +302,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info.per_day = 3; info.total_max = 4; info.category = "Technology & Computing-Software"; + info.dayparts.push_back(daypart_info); info.geo_targets = { "US" }; info.target_url = "https://brave.com"; info.title = "Test Ad 1 Title"; @@ -332,6 +341,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -344,6 +354,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.title = "Test Ad 1 Title"; @@ -363,6 +374,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Technology & Computing-Software"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.title = "Test Ad 2 Title"; @@ -400,6 +412,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info; info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -412,6 +425,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info.per_day = 3; info.total_max = 4; info.category = "Technology & Computing-Software"; + info.dayparts.push_back(daypart_info); info.geo_targets = { "US" }; info.target_url = "https://brave.com"; info.title = "Test Ad 1 Title"; @@ -446,6 +460,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info; info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -458,6 +473,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info.per_day = 3; info.total_max = 4; info.category = "Technology & Computing-Software"; + info.dayparts.push_back(daypart_info); info.geo_targets = { "US" }; info.target_url = "https://brave.com"; info.title = "Test Ad 1 Title"; @@ -494,6 +510,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -506,6 +523,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.title = "Test Ad 1 Title"; @@ -525,6 +543,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Food & Drink"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.title = "Test Ad 2 Title"; @@ -544,6 +563,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_3.per_day = 3; info_3.total_max = 4; info_3.category = "Automobiles"; + info_3.dayparts.push_back(daypart_info); info_3.geo_targets = { "US" }; info_3.target_url = "https://brave.com"; info_3.title = "Test Ad 3 Title"; @@ -583,6 +603,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -595,6 +616,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.title = "Test Ad 1 Title"; @@ -614,6 +636,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Technology & Computing-Software"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.title = "Test Ad 2 Title"; @@ -652,6 +675,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, CreativeAdNotificationList creative_ad_notifications; + CreativeDaypartInfo daypart_info; CreativeAdNotificationInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -664,6 +688,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.title = "Test Ad 1 Title"; @@ -683,6 +708,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Food & Drink"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.title = "Test Ad 2 Title"; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.cc index 9a824472e107..1196955fc7e5 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.cc @@ -40,6 +40,7 @@ CreativeNewTabPageAds::CreativeNewTabPageAds( campaigns_database_table_(std::make_unique(ads_)), categories_database_table_(std::make_unique(ads_)), creative_ads_database_table_(std::make_unique(ads_)), + dayparts_database_table_(std::make_unique(ads_)), geo_targets_database_table_(std::make_unique(ads_)) { DCHECK(ads_); } @@ -69,6 +70,7 @@ void CreativeNewTabPageAds::Save( transaction.get(), creative_ads); creative_ads_database_table_->InsertOrUpdate( transaction.get(), creative_ads); + dayparts_database_table_->InsertOrUpdate(transaction.get(), creative_ads); geo_targets_database_table_->InsertOrUpdate( transaction.get(), creative_ads); } @@ -115,7 +117,10 @@ void CreativeNewTabPageAds::GetForCreativeInstanceId( "ca.target_url, " "can.company_name, " "can.alt, " - "cam.ptr " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " "FROM %s AS can " "INNER JOIN campaigns AS cam " "ON cam.campaign_id = can.campaign_id " @@ -125,6 +130,8 @@ void CreativeNewTabPageAds::GetForCreativeInstanceId( "ON ca.creative_set_id = can.creative_set_id " "INNER JOIN geo_targets AS gt " "ON gt.campaign_id = can.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = can.campaign_id " "WHERE can.creative_instance_id = '%s'", get_table_name().c_str(), creative_instance_id.c_str()); @@ -150,7 +157,10 @@ void CreativeNewTabPageAds::GetForCreativeInstanceId( DBCommand::RecordBindingType::STRING_TYPE, // target_url DBCommand::RecordBindingType::STRING_TYPE, // company_name DBCommand::RecordBindingType::STRING_TYPE, // alt - DBCommand::RecordBindingType::DOUBLE_TYPE // ptr + DBCommand::RecordBindingType::DOUBLE_TYPE, // ptr + DBCommand::RecordBindingType::STRING_TYPE, // dayparts->dow + DBCommand::RecordBindingType::INT_TYPE, // dayparts->start_minute + DBCommand::RecordBindingType::INT_TYPE // dayparts->end_minute }; DBTransactionPtr transaction = DBTransaction::New(); @@ -187,7 +197,10 @@ void CreativeNewTabPageAds::GetForCategories( "ca.target_url, " "can.company_name, " "can.alt, " - "cam.ptr " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " "FROM %s AS can " "INNER JOIN campaigns AS cam " "ON cam.campaign_id = can.campaign_id " @@ -197,6 +210,8 @@ void CreativeNewTabPageAds::GetForCategories( "ON ca.creative_set_id = can.creative_set_id " "INNER JOIN geo_targets AS gt " "ON gt.campaign_id = can.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = can.campaign_id " "WHERE c.category IN %s " "AND %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", get_table_name().c_str(), @@ -230,7 +245,10 @@ void CreativeNewTabPageAds::GetForCategories( DBCommand::RecordBindingType::STRING_TYPE, // target_url DBCommand::RecordBindingType::STRING_TYPE, // company_name DBCommand::RecordBindingType::STRING_TYPE, // alt - DBCommand::RecordBindingType::DOUBLE_TYPE // ptr + DBCommand::RecordBindingType::DOUBLE_TYPE, // ptr + DBCommand::RecordBindingType::STRING_TYPE, // dayparts->dow + DBCommand::RecordBindingType::INT_TYPE, // dayparts->start_minute + DBCommand::RecordBindingType::INT_TYPE // dayparts->end_minute }; DBTransactionPtr transaction = DBTransaction::New(); @@ -261,7 +279,10 @@ void CreativeNewTabPageAds::GetAll( "ca.target_url, " "can.company_name, " "can.alt, " - "cam.ptr " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " "FROM %s AS can " "INNER JOIN campaigns AS cam " "ON cam.campaign_id = can.campaign_id " @@ -271,6 +292,8 @@ void CreativeNewTabPageAds::GetAll( "ON ca.creative_set_id = can.creative_set_id " "INNER JOIN geo_targets AS gt " "ON gt.campaign_id = can.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = can.campaign_id " "WHERE %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", get_table_name().c_str(), NowAsString().c_str()); @@ -296,7 +319,10 @@ void CreativeNewTabPageAds::GetAll( DBCommand::RecordBindingType::STRING_TYPE, // target_url DBCommand::RecordBindingType::STRING_TYPE, // company_name DBCommand::RecordBindingType::STRING_TYPE, // alt - DBCommand::RecordBindingType::DOUBLE_TYPE // ptr + DBCommand::RecordBindingType::DOUBLE_TYPE, // ptr + DBCommand::RecordBindingType::STRING_TYPE, // dayparts->dow + DBCommand::RecordBindingType::INT_TYPE, // dayparts->start_minute + DBCommand::RecordBindingType::INT_TYPE // dayparts->end_minute }; DBTransactionPtr transaction = DBTransaction::New(); @@ -488,6 +514,12 @@ CreativeNewTabPageAdInfo CreativeNewTabPageAds::GetFromRecord( creative_new_tab_page_ad.alt = ColumnString(record, 15); creative_new_tab_page_ad.ptr = ColumnDouble(record, 16); + CreativeDaypartInfo daypart; + daypart.dow = ColumnString(record, 17); + daypart.start_minute = ColumnInt(record, 18); + daypart.end_minute = ColumnInt(record, 19); + creative_new_tab_page_ad.dayparts.push_back(daypart); + return creative_new_tab_page_ad; } diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.h index abef67b29da6..2be6f399dcb2 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table.h @@ -17,6 +17,7 @@ #include "bat/ads/internal/database/tables/campaigns_database_table.h" #include "bat/ads/internal/database/tables/categories_database_table.h" #include "bat/ads/internal/database/tables/creative_ads_database_table.h" +#include "bat/ads/internal/database/tables/dayparts_database_table.h" #include "bat/ads/internal/database/tables/geo_targets_database_table.h" #include "bat/ads/mojom.h" #include "bat/ads/result.h" @@ -110,6 +111,7 @@ class CreativeNewTabPageAds : public Table { std::unique_ptr campaigns_database_table_; std::unique_ptr categories_database_table_; std::unique_ptr creative_ads_database_table_; + std::unique_ptr dayparts_database_table_; std::unique_ptr geo_targets_database_table_; }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc index af6f9268a146..66a56365e5e0 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc @@ -127,6 +127,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -139,6 +140,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.company_name = "Test Ad 1 Title"; @@ -158,6 +160,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Technology & Computing-Software"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.company_name = "Test Ad 2 Title"; @@ -194,6 +197,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreateOrOpenDatabase(); + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdList creative_new_tab_page_ads; CreativeNewTabPageAdInfo info_1; @@ -208,6 +212,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.company_name = "Test Ad 1 Title"; @@ -227,6 +232,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Technology & Computing-Software"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.company_name = "Test Ad 2 Title"; @@ -246,6 +252,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_3.per_day = 3; info_3.total_max = 4; info_3.category = "Technology & Computing-Software"; + info_3.dayparts.push_back(daypart_info); info_3.geo_targets = { "US" }; info_3.target_url = "https://brave.com"; info_3.company_name = "Test Ad 3 Title"; @@ -282,6 +289,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info; info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -294,6 +302,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info.per_day = 3; info.total_max = 4; info.category = "Technology & Computing-Software"; + info.dayparts.push_back(daypart_info); info.geo_targets = { "US" }; info.target_url = "https://brave.com"; info.company_name = "Test Ad 1 Title"; @@ -332,6 +341,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -344,6 +354,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.company_name = "Test Ad 1 Title"; @@ -363,6 +374,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Technology & Computing-Software"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.company_name = "Test Ad 2 Title"; @@ -400,6 +412,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info; info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -412,6 +425,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info.per_day = 3; info.total_max = 4; info.category = "Technology & Computing-Software"; + info.dayparts.push_back(daypart_info); info.geo_targets = { "US" }; info.target_url = "https://brave.com"; info.company_name = "Test Ad 1 Title"; @@ -446,6 +460,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info; info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -458,6 +473,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info.per_day = 3; info.total_max = 4; info.category = "Technology & Computing-Software"; + info.dayparts.push_back(daypart_info); info.geo_targets = { "US" }; info.target_url = "https://brave.com"; info.company_name = "Test Ad 1 Title"; @@ -488,6 +504,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info; info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -500,6 +517,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info.per_day = 3; info.total_max = 4; info.category = "Technology & Computing-Software"; + info.dayparts.push_back(daypart_info); info.geo_targets = { "US" }; info.target_url = "https://brave.com"; info.company_name = "Test Ad 1 Title"; @@ -534,6 +552,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info; info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -546,6 +565,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info.per_day = 3; info.total_max = 4; info.category = "Technology & Computing-Software"; + info.dayparts.push_back(daypart_info); info.geo_targets = { "US" }; info.target_url = "https://brave.com"; info.company_name = "Test Ad 1 Title"; @@ -582,6 +602,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -594,6 +615,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.company_name = "Test Ad 1 Title"; @@ -613,6 +635,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Food & Drink"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.company_name = "Test Ad 2 Title"; @@ -632,6 +655,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_3.per_day = 3; info_3.total_max = 4; info_3.category = "Automobiles"; + info_3.dayparts.push_back(daypart_info); info_3.geo_targets = { "US" }; info_3.target_url = "https://brave.com"; info_3.company_name = "Test Ad 3 Title"; @@ -671,6 +695,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -683,6 +708,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.company_name = "Test Ad 1 Title"; @@ -702,6 +728,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Technology & Computing-Software"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.company_name = "Test Ad 2 Title"; @@ -740,6 +767,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativeDaypartInfo daypart_info; CreativeNewTabPageAdInfo info_1; info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; @@ -752,6 +780,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_1.per_day = 3; info_1.total_max = 4; info_1.category = "Technology & Computing-Software"; + info_1.dayparts.push_back(daypart_info); info_1.geo_targets = { "US" }; info_1.target_url = "https://brave.com"; info_1.company_name = "Test Ad 1 Title"; @@ -771,6 +800,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableTest, info_2.per_day = 3; info_2.total_max = 4; info_2.category = "Food & Drink"; + info_2.dayparts.push_back(daypart_info); info_2.geo_targets = { "US" }; info_2.target_url = "https://brave.com"; info_2.company_name = "Test Ad 2 Title"; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/dayparts_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/dayparts_database_table.cc new file mode 100644 index 000000000000..9cdf23d116cf --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/dayparts_database_table.cc @@ -0,0 +1,167 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/database/tables/dayparts_database_table.h" + +#include + +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "bat/ads/internal/ads_impl.h" +#include "bat/ads/internal/bundle/creative_ad_info.h" +#include "bat/ads/internal/database/database_statement_util.h" +#include "bat/ads/internal/database/database_table_util.h" +#include "bat/ads/internal/database/database_util.h" +#include "bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h" +#include "bat/ads/internal/logging.h" + +namespace ads { +namespace database { +namespace table { + +using std::placeholders::_1; + +namespace { +const char kTableName[] = "dayparts"; +} // namespace + +Dayparts::Dayparts( + AdsImpl* ads) + : ads_(ads) { + DCHECK(ads_); +} + +Dayparts::~Dayparts() = default; + +void Dayparts::InsertOrUpdate( + DBTransaction* transaction, + const CreativeAdList& creative_ads) { + DCHECK(transaction); + + if (creative_ads.empty()) { + return; + } + + DBCommandPtr command = DBCommand::New(); + command->type = DBCommand::Type::RUN; + command->command = BuildInsertOrUpdateQuery(command.get(), + creative_ads); + + transaction->commands.push_back(std::move(command)); +} + +void Dayparts::Delete( + ResultCallback callback) { + DBTransactionPtr transaction = DBTransaction::New(); + + util::Delete(transaction.get(), get_table_name()); + + ads_->get_ads_client()->RunDBTransaction(std::move(transaction), + std::bind(&OnResultCallback, _1, callback)); +} + +std::string Dayparts::get_table_name() const { + return kTableName; +} + +void Dayparts::Migrate( + DBTransaction* transaction, + const int to_version) { + DCHECK(transaction); + + switch (to_version) { + case 4: { + MigrateToV4(transaction); + break; + } + + default: { + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +int Dayparts::BindParameters( + DBCommand* command, + const CreativeAdList& creative_ads) { + DCHECK(command); + + int count = 0; + int index = 0; + + for (const auto& creative_ad : creative_ads) { + for (const auto& daypart : creative_ad.dayparts) { + BindString(command, index++, + creative_ad.campaign_id); + BindString(command, index++, daypart.dow); + BindInt(command, index++, daypart.start_minute); + BindInt(command, index++, daypart.end_minute); + + count++; + } + } + + return count; +} + +std::string Dayparts::BuildInsertOrUpdateQuery( + DBCommand* command, + const CreativeAdList& creative_ads) { + const int count = BindParameters(command, creative_ads); + + return base::StringPrintf( + "INSERT OR REPLACE INTO %s " + "(campaign_id, " + "dow, " + "start_minute, " + "end_minute) VALUES %s", + get_table_name().c_str(), + BuildBindingParameterPlaceholders(4, count).c_str()); +} + +void Dayparts::CreateTableV4( + DBTransaction* transaction) { + DCHECK(transaction); + + const std::string query = base::StringPrintf( + "CREATE TABLE %s " + "(campaign_id TEXT NOT NULL, " + "dow TEXT NOT NULL, " + "start_minute INT NOT NULL, " + "end_minute INT NOT NULL, " + "PRIMARY KEY (campaign_id, dow, start_minute, end_minute), " + "UNIQUE(campaign_id, dow, start_minute, end_minute) " + "ON CONFLICT REPLACE)", + get_table_name().c_str()); + + DBCommandPtr command = DBCommand::New(); + command->type = DBCommand::Type::EXECUTE; + command->command = query; + + transaction->commands.push_back(std::move(command)); +} + +void Dayparts::CreateIndexV4( + DBTransaction* transaction) { + DCHECK(transaction); + + util::CreateIndex(transaction, get_table_name(), "campaign_id"); +} + +void Dayparts::MigrateToV4( + DBTransaction* transaction) { + DCHECK(transaction); + + util::Drop(transaction, get_table_name()); + + CreateTableV4(transaction); + CreateIndexV4(transaction); +} + +} // namespace table +} // namespace database +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/dayparts_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/dayparts_database_table.h new file mode 100644 index 000000000000..a05a51b6ff62 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/dayparts_database_table.h @@ -0,0 +1,65 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +#ifndef BAT_ADS_INTERNAL_DATABASE_DAYPARTS_DATABASE_TABLE_H_ +#define BAT_ADS_INTERNAL_DATABASE_DAYPARTS_DATABASE_TABLE_H_ + +#include + +#include "bat/ads/ads_client.h" +#include "bat/ads/internal/bundle/creative_ad_info.h" +#include "bat/ads/internal/database/database_table.h" + +namespace ads { + +class AdsImpl; + +namespace database { +namespace table { + +class Dayparts : public Table { + public: + explicit Dayparts( + AdsImpl* ads); + + ~Dayparts() override; + + void InsertOrUpdate( + DBTransaction* transaction, + const CreativeAdList& creative_ads); + + void Delete( + ResultCallback callback); + + std::string get_table_name() const override; + + void Migrate( + DBTransaction* transaction, + const int to_version) override; + + private: + int BindParameters( + DBCommand* command, + const CreativeAdList& creative_ads); + + std::string BuildInsertOrUpdateQuery( + DBCommand* command, + const CreativeAdList& creative_ads); + + void CreateTableV4( + DBTransaction* transaction); + void CreateIndexV4( + DBTransaction* transaction); + void MigrateToV4( + DBTransaction* transaction); + + AdsImpl* ads_; // NOT OWNED +}; + +} // namespace table +} // namespace database +} // namespace ads + +#endif // BAT_ADS_INTERNAL_DATABASE_DAYPARTS_DATABASE_TABLE_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.cc new file mode 100644 index 000000000000..005412b63063 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.cc @@ -0,0 +1,100 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h" + +#include +#include + +#include "base/strings/stringprintf.h" +#include "base/strings/string_number_conversions.h" +#include "bat/ads/internal/ads_impl.h" +#include "bat/ads/internal/frequency_capping/frequency_capping_util.h" + +namespace ads { + +DaypartFrequencyCap::DaypartFrequencyCap( + const AdsImpl* const ads) + : ads_(ads) { + DCHECK(ads_); +} + +DaypartFrequencyCap::~DaypartFrequencyCap() = default; + +bool DaypartFrequencyCap::ShouldExclude( + const CreativeAdInfo& ad) { + if (!DoesRespectCap(ad)) { + last_message_ = base::StringPrintf("creativeSetId %s excluded as not " + "within the scheduled timeslot", ad.creative_set_id.c_str()); + + return true; + } + + return false; +} + +std::string DaypartFrequencyCap::get_last_message() const { + return last_message_; +} + +bool DaypartFrequencyCap::DoesRespectCap( + const CreativeAdInfo& ad) const { + // If there's no day part specified, let it be displayed + if (ad.dayparts.empty()) { + return true; + } + + const std::string current_dow = DaypartFrequencyCap::GetCurrentDayOfWeek(); + std::string days_of_week; + int current_minutes_from_start = + DaypartFrequencyCap::GetCurrentLocalMinutesFromStart(); + int start_time; + int end_time; + + for (const CreativeDaypartInfo& daypart : ad.dayparts) { + days_of_week = daypart.dow; + start_time = daypart.start_minute; + end_time = daypart.end_minute; + + if (DaypartFrequencyCap::HasDayOfWeekMatch(current_dow, days_of_week) + && DaypartFrequencyCap::HasTimeSlotMatch( + current_minutes_from_start, + start_time, end_time)) { + return true; + } + } + return false; +} + +bool DaypartFrequencyCap::HasDayOfWeekMatch( + const std::string& current_dow, + const std::string& days_of_week) const { + return days_of_week.find(current_dow) != std::string::npos; +} + +bool DaypartFrequencyCap::HasTimeSlotMatch( + const int current_minutes_from_start, + const int start_time, + const int end_time) const { + + return start_time <= current_minutes_from_start && + current_minutes_from_start <= end_time; +} + +std::string DaypartFrequencyCap::GetCurrentDayOfWeek() const { + const base::Time now = base::Time::Now(); + base::Time::Exploded exploded; + now.LocalExplode(&exploded); + return base::NumberToString(exploded.day_of_week); +} + +int DaypartFrequencyCap::GetCurrentLocalMinutesFromStart() const { + const base::Time now = base::Time::Now(); + base::Time::Exploded exploded; + now.LocalExplode(&exploded); + return (base::Time::kMinutesPerHour * exploded.hour) + exploded.minute; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h new file mode 100644 index 000000000000..018d9b161ad2 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h @@ -0,0 +1,58 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +#ifndef BAT_ADS_INTERNAL_FREQUENCY_CAPPING_EXCLUSION_RULES_DAYPART_FREQUENCY_CAP_H_ // NOLINT +#define BAT_ADS_INTERNAL_FREQUENCY_CAPPING_EXCLUSION_RULES_DAYPART_FREQUENCY_CAP_H_ // NOLINT + +#include +#include + +#include "bat/ads/internal/bundle/creative_ad_info.h" +#include "bat/ads/internal/frequency_capping/exclusion_rules/exclusion_rule.h" + +namespace ads { + +class AdsImpl; + +class DaypartFrequencyCap : public ExclusionRule { + public: + DaypartFrequencyCap( + const AdsImpl* const ads); + + ~DaypartFrequencyCap() override; + + DaypartFrequencyCap( + const DaypartFrequencyCap&) = delete; + DaypartFrequencyCap& operator=( + const DaypartFrequencyCap&) = delete; + + bool ShouldExclude( + const CreativeAdInfo& ad) override; + + std::string get_last_message() const override; + + private: + const AdsImpl* const ads_; // NOT OWNED + + std::string last_message_; + + bool DoesRespectCap( + const CreativeAdInfo& ad) const; + + bool HasDayOfWeekMatch( + const std::string& current_dow, + const std::string& days_of_week) const; + bool HasTimeSlotMatch( + const int current_minutes_from_start, + const int start_time, + const int end_time) const; + + std::string GetCurrentDayOfWeek() const; + int GetCurrentLocalMinutesFromStart() const; +}; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_FREQUENCY_CAPPING_EXCLUSION_RULES_SUBDIVISION_TARGETING_FREQUENCY_CAP_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap_unittest.cc new file mode 100644 index 000000000000..e38d1dad8496 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap_unittest.cc @@ -0,0 +1,296 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/frequency_capping/exclusion_rules/daypart_frequency_cap.h" + +#include + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/strings/string_number_conversions.h" +#include "base/test/task_environment.h" +#include "brave/components/l10n/browser/locale_helper_mock.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "bat/ads/internal/ads_client_mock.h" +#include "bat/ads/internal/ads_impl.h" +#include "bat/ads/internal/bundle/creative_ad_info.h" +#include "bat/ads/internal/frequency_capping/frequency_capping_unittest_util.h" +#include "bat/ads/internal/platform/platform_helper_mock.h" +#include "bat/ads/internal/unittest_util.h" +#include "bat/ads/internal/time_util.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +using ::testing::NiceMock; +using ::testing::Return; + +namespace ads { + +namespace { + +const char kCreativeSetId[] = "654f10df-fbc4-4a92-8d43-2edf73734a60"; + +} // namespace + +class BatAdsDaypartFrequencyCapTest : public ::testing::Test { + protected: + BatAdsDaypartFrequencyCapTest() + : ads_client_mock_(std::make_unique>()), + ads_(std::make_unique(ads_client_mock_.get())), + locale_helper_mock_(std::make_unique< + NiceMock>()), + platform_helper_mock_(std::make_unique< + NiceMock>()), + frequency_cap_(std::make_unique< + DaypartFrequencyCap>(ads_.get())) { + // You can do set-up work for each test here + brave_l10n::LocaleHelper::GetInstance()->set_for_testing( + locale_helper_mock_.get()); + + PlatformHelper::GetInstance()->set_for_testing(platform_helper_mock_.get()); + } + + ~BatAdsDaypartFrequencyCapTest() override { + // You can do clean-up work that doesn't throw exceptions here + } + + // If the constructor and destructor are not enough for setting up and + // cleaning up each test, you can use the following methods + + void SetUp() override { + // Code here will be called immediately after the constructor (right before + // each test) + + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + const base::FilePath path = temp_dir_.GetPath(); + + SetBuildChannel(false, "test"); + + ON_CALL(*locale_helper_mock_, GetLocale()) + .WillByDefault(Return("en-US")); + + MockPlatformHelper(platform_helper_mock_, PlatformType::kMacOS); + + ads_->OnWalletUpdated("c387c2d8-a26d-4451-83e4-5c0c6fd942be", + "5BEKM1Y7xcRSg/1q8in/+Lki2weFZQB+UMYZlRw8ql8="); + + MockLoad(ads_client_mock_); + MockLoadUserModelForId(ads_client_mock_); + MockLoadResourceForId(ads_client_mock_); + MockSave(ads_client_mock_); + + database_ = std::make_unique(path.AppendASCII("database.sqlite")); + MockRunDBTransaction(ads_client_mock_, database_); + + Initialize(ads_); + } + + void TearDown() override { + // Code here will be called immediately after each test (right before the + // destructor) + } + + // Objects declared here can be used by all tests in the test case + + base::test::TaskEnvironment task_environment_; + + base::ScopedTempDir temp_dir_; + + std::unique_ptr ads_client_mock_; + std::unique_ptr ads_; + std::unique_ptr locale_helper_mock_; + std::unique_ptr platform_helper_mock_; + std::unique_ptr frequency_cap_; + std::unique_ptr database_; +}; + +TEST_F(BatAdsDaypartFrequencyCapTest, AllowIfDaypartsIsEmpty) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetId; + + // Act + const bool should_exclude = frequency_cap_->ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + +TEST_F(BatAdsDaypartFrequencyCapTest, AllowIfRightDayAndHours) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetId; + + base::Time::Exploded exploded; + base::Time::Now().LocalExplode(&exploded); + const int current_time = base::Time::kMinutesPerHour * exploded.hour + + exploded.minute; + + CreativeDaypartInfo daypart_info; + daypart_info.dow = base::NumberToString(exploded.day_of_week); + daypart_info.start_minute = current_time - base::Time::kMinutesPerHour; + daypart_info.end_minute = current_time + base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info); + + // Act + const bool should_exclude = frequency_cap_->ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + +TEST_F(BatAdsDaypartFrequencyCapTest, AllowForMultipleDays) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetId; + + base::Time::Exploded exploded; + base::Time::Now().LocalExplode(&exploded); + const int current_time = base::Time::kMinutesPerHour * exploded.hour + + exploded.minute; + + CreativeDaypartInfo daypart_info; + daypart_info.start_minute = current_time - base::Time::kMinutesPerHour; + daypart_info.end_minute = current_time + base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info); + + // Act + const bool should_exclude = frequency_cap_->ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + +TEST_F(BatAdsDaypartFrequencyCapTest, AllowIfOneMatchExists) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetId; + + base::Time::Exploded exploded; + base::Time::Now().LocalExplode(&exploded); + const int current_time = base::Time::kMinutesPerHour * exploded.hour + + exploded.minute; + std::string tomorrow_dow = + base::NumberToString((exploded.day_of_week + 1) % 7); + std::string current_dow = base::NumberToString(exploded.day_of_week); + + CreativeDaypartInfo daypart_info; + daypart_info.dow = tomorrow_dow; + daypart_info.start_minute = current_time - 2 * base::Time::kMinutesPerHour; + daypart_info.end_minute = current_time - base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info); + + CreativeDaypartInfo daypart_info_2; + daypart_info_2.dow = tomorrow_dow; + daypart_info_2.start_minute = current_time + 2 * base::Time::kMinutesPerHour; + daypart_info_2.end_minute = current_time + 3 * base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info_2); + + CreativeDaypartInfo daypart_info_3; + daypart_info_3.dow = current_dow; + daypart_info_3.start_minute = current_time - base::Time::kMinutesPerHour; + daypart_info_3.end_minute = current_time + base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info_3); + + // Act + const bool should_exclude = frequency_cap_->ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + +TEST_F(BatAdsDaypartFrequencyCapTest, DisallowIfNoMatches) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetId; + + base::Time::Exploded exploded; + base::Time::Now().LocalExplode(&exploded); + const int current_time = base::Time::kMinutesPerHour * exploded.hour + + exploded.minute; + std::string tomorrow_dow = + base::NumberToString((exploded.day_of_week + 1) % 7); + std::string current_dow = base::NumberToString(exploded.day_of_week); + + CreativeDaypartInfo daypart_info; + daypart_info.dow = tomorrow_dow; + daypart_info.start_minute = current_time - 2 * base::Time::kMinutesPerHour; + daypart_info.end_minute = current_time - base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info); + + CreativeDaypartInfo daypart_info_2; + daypart_info_2.dow = tomorrow_dow; + daypart_info_2.start_minute = current_time + 2 * base::Time::kMinutesPerHour; + daypart_info_2.end_minute = current_time + 3 * base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info_2); + + CreativeDaypartInfo daypart_info_3; + daypart_info_3.dow = current_dow; + daypart_info_3.start_minute = current_time + base::Time::kMinutesPerHour; + daypart_info_3.end_minute = current_time + 2 * base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info_3); + + // Act + const bool should_exclude = frequency_cap_->ShouldExclude(ad); + + // Assert + EXPECT_TRUE(should_exclude); +} + + +TEST_F(BatAdsDaypartFrequencyCapTest, DisallowIfWrongDay) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetId; + + base::Time::Exploded exploded; + base::Time::Now().LocalExplode(&exploded); + const int current_time = base::Time::kMinutesPerHour * exploded.hour + + exploded.minute; + + // Go to next day + std::string tomorrow_dow = + base::NumberToString((exploded.day_of_week + 1) % 7); + + CreativeDaypartInfo daypart_info; + daypart_info.dow = tomorrow_dow; + daypart_info.start_minute = current_time - 2 * base::Time::kMinutesPerHour; + daypart_info.end_minute = current_time - base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info); + + // Act + const bool should_exclude = frequency_cap_->ShouldExclude(ad); + + // Assert + EXPECT_TRUE(should_exclude); +} + +TEST_F(BatAdsDaypartFrequencyCapTest, DisallowIfWrongHours) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetId; + + base::Time::Exploded exploded; + base::Time::Now().LocalExplode(&exploded); + const int current_time = base::Time::kMinutesPerHour * exploded.hour + + exploded.minute; + std::string current_dow = base::NumberToString(exploded.day_of_week); + + CreativeDaypartInfo daypart_info; + daypart_info.dow = current_dow; + daypart_info.start_minute = current_time - base::Time::kMinutesPerHour; + daypart_info.end_minute = current_time - base::Time::kMinutesPerHour; + ad.dayparts.push_back(daypart_info); + + // Act + const bool should_exclude = frequency_cap_->ShouldExclude(ad); + + // Assert + EXPECT_TRUE(should_exclude); +} + +} // namespace ads