diff --git a/components/brave_ads/browser/ads_service.h b/components/brave_ads/browser/ads_service.h index ad9dc520cedd..a5022e57e7b4 100644 --- a/components/brave_ads/browser/ads_service.h +++ b/components/brave_ads/browser/ads_service.h @@ -115,10 +115,15 @@ class AdsService : public KeyedService { const std::string& id) = 0; virtual void OnNewTabPageAdEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const ads::mojom::BraveAdsNewTabPageAdEventType event_type) = 0; + virtual void OnPromotedContentAdEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const ads::mojom::BraveAdsPromotedContentAdEventType event_type) = 0; + virtual void ReconcileAdRewards() = 0; virtual void GetAdsHistory( diff --git a/components/brave_ads/browser/ads_service_impl.cc b/components/brave_ads/browser/ads_service_impl.cc index 0182ece741cf..a005c574f7fe 100644 --- a/components/brave_ads/browser/ads_service_impl.cc +++ b/components/brave_ads/browser/ads_service_impl.cc @@ -1016,14 +1016,25 @@ void AdsServiceImpl::OnViewAdNotification( } void AdsServiceImpl::OnNewTabPageAdEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const ads::NewTabPageAdEventType event_type) { if (!connected()) { return; } - bat_ads_->OnNewTabPageAdEvent(wallpaper_id, creative_instance_id, event_type); + bat_ads_->OnNewTabPageAdEvent(uuid, creative_instance_id, event_type); +} + +void AdsServiceImpl::OnPromotedContentAdEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const ads::PromotedContentAdEventType event_type) { + if (!connected()) { + return; + } + + bat_ads_->OnPromotedContentAdEvent(uuid, creative_instance_id, event_type); } void AdsServiceImpl::RetryViewingAdNotification( diff --git a/components/brave_ads/browser/ads_service_impl.h b/components/brave_ads/browser/ads_service_impl.h index 1e40b8940e2e..c42570883e5d 100644 --- a/components/brave_ads/browser/ads_service_impl.h +++ b/components/brave_ads/browser/ads_service_impl.h @@ -125,10 +125,15 @@ class AdsServiceImpl : public AdsService, const std::string& id) override; void OnNewTabPageAdEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const ads::NewTabPageAdEventType event_type) override; + void OnPromotedContentAdEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const ads::PromotedContentAdEventType event_type) override; + void ReconcileAdRewards() override; void GetAdsHistory( diff --git a/components/brave_ads/test/BUILD.gn b/components/brave_ads/test/BUILD.gn index 7ebb89a4c988..9abda3c5f771 100644 --- a/components/brave_ads/test/BUILD.gn +++ b/components/brave_ads/test/BUILD.gn @@ -48,6 +48,8 @@ source_set("brave_ads_unit_tests") { "//brave/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_test.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_test.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/features/bandits/epsilon_greedy_bandit_features_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/features/purchase_intent/purchase_intent_features_unittest.cc", @@ -61,6 +63,7 @@ source_set("brave_ads_unit_tests") { "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/new_tab_page_ad_uuid_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/subdivision_targeting_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap_unittest.cc", @@ -77,6 +80,8 @@ source_set("brave_ads_unit_tests") { "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/network_connection_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/new_tab_page_ads_per_day_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/new_tab_page_ads_per_hour_frequency_cap_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/unblinded_tokens_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/user_activity_frequency_cap_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/legacy_migration/legacy_migration_util_unittest.cc", diff --git a/components/services/bat_ads/bat_ads_impl.cc b/components/services/bat_ads/bat_ads_impl.cc index 8037488fad37..c1452ed6c66e 100644 --- a/components/services/bat_ads/bat_ads_impl.cc +++ b/components/services/bat_ads/bat_ads_impl.cc @@ -132,10 +132,17 @@ void BatAdsImpl::OnAdNotificationEvent( } void BatAdsImpl::OnNewTabPageAdEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const ads::NewTabPageAdEventType event_type) { - ads_->OnNewTabPageAdEvent(wallpaper_id, creative_instance_id, event_type); + ads_->OnNewTabPageAdEvent(uuid, creative_instance_id, event_type); +} + +void BatAdsImpl::OnPromotedContentAdEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const ads::PromotedContentAdEventType event_type) { + ads_->OnPromotedContentAdEvent(uuid, creative_instance_id, event_type); } void BatAdsImpl::RemoveAllHistory( diff --git a/components/services/bat_ads/bat_ads_impl.h b/components/services/bat_ads/bat_ads_impl.h index 423a0c93eae6..369d962fcbe2 100644 --- a/components/services/bat_ads/bat_ads_impl.h +++ b/components/services/bat_ads/bat_ads_impl.h @@ -81,10 +81,15 @@ class BatAdsImpl : const ads::AdNotificationEventType event_type) override; void OnNewTabPageAdEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const ads::NewTabPageAdEventType event_type) override; + void OnPromotedContentAdEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const ads::PromotedContentAdEventType event_type) override; + void RemoveAllHistory( RemoveAllHistoryCallback callback) override; diff --git a/components/services/bat_ads/public/interfaces/bat_ads.mojom b/components/services/bat_ads/public/interfaces/bat_ads.mojom index dcf79002d564..5f47fec75431 100644 --- a/components/services/bat_ads/public/interfaces/bat_ads.mojom +++ b/components/services/bat_ads/public/interfaces/bat_ads.mojom @@ -76,7 +76,8 @@ interface BatAds { OnTabClosed(int32 tab_id); GetAdNotification(string uuid) => (string json); OnAdNotificationEvent(string uuid, ads.mojom.BraveAdsAdNotificationEventType event_type); - OnNewTabPageAdEvent(string wallpaper_id, string creative_instance_id, ads.mojom.BraveAdsNewTabPageAdEventType event_type); + OnNewTabPageAdEvent(string uuid, string creative_instance_id, ads.mojom.BraveAdsNewTabPageAdEventType event_type); + OnPromotedContentAdEvent(string uuid, string creative_instance_id, ads.mojom.BraveAdsPromotedContentAdEventType event_type); RemoveAllHistory() => (int32 result); OnWalletUpdated(string payment_id, string seed); ReconcileAdRewards(); diff --git a/vendor/bat-native-ads/BUILD.gn b/vendor/bat-native-ads/BUILD.gn index 861129f66d7f..67b728a33afc 100644 --- a/vendor/bat-native-ads/BUILD.gn +++ b/vendor/bat-native-ads/BUILD.gn @@ -80,6 +80,7 @@ source_set("headers") { "include/bat/ads/export.h", "include/bat/ads/new_tab_page_ad_info.h", "include/bat/ads/pref_names.h", + "include/bat/ads/promoted_content_ad_info.h", "include/bat/ads/result.h", "include/bat/ads/statement_info.h", "include/bat/ads/transaction_info.h", @@ -160,6 +161,12 @@ source_set("ads") { "src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_factory.h", "src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_viewed.cc", "src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_viewed.h", + "src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.cc", + "src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.h", + "src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.cc", + "src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.h", + "src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.cc", + "src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.h", "src/bat/ads/internal/ad_pacing/ad_notifications/ad_notification_pacing.cc", "src/bat/ads/internal/ad_pacing/ad_notifications/ad_notification_pacing.h", "src/bat/ads/internal/ad_server/ad_server.cc", @@ -173,12 +180,12 @@ source_set("ads") { "src/bat/ads/internal/ad_serving/ad_targeting/geographic/subdivision/get_subdivision_url_request_builder.h", "src/bat/ads/internal/ad_serving/ad_targeting/geographic/subdivision/subdivision_targeting.cc", "src/bat/ads/internal/ad_serving/ad_targeting/geographic/subdivision/subdivision_targeting.h", - "src/bat/ads/internal/ad_serving/ad_targeting/models/behavioral/bandits/epsilon_greedy_bandit_model_values.h", "src/bat/ads/internal/ad_serving/ad_targeting/models/behavioral/bandits/epsilon_greedy_bandit_model.cc", "src/bat/ads/internal/ad_serving/ad_targeting/models/behavioral/bandits/epsilon_greedy_bandit_model.h", - "src/bat/ads/internal/ad_serving/ad_targeting/models/behavioral/purchase_intent/purchase_intent_model_values.h", + "src/bat/ads/internal/ad_serving/ad_targeting/models/behavioral/bandits/epsilon_greedy_bandit_model_values.h", "src/bat/ads/internal/ad_serving/ad_targeting/models/behavioral/purchase_intent/purchase_intent_model.cc", "src/bat/ads/internal/ad_serving/ad_targeting/models/behavioral/purchase_intent/purchase_intent_model.h", + "src/bat/ads/internal/ad_serving/ad_targeting/models/behavioral/purchase_intent/purchase_intent_model_values.h", "src/bat/ads/internal/ad_serving/ad_targeting/models/contextual/text_classification/text_classification_model.cc", "src/bat/ads/internal/ad_serving/ad_targeting/models/contextual/text_classification/text_classification_model.h", "src/bat/ads/internal/ad_serving/ad_targeting/models/model.h", @@ -214,12 +221,12 @@ source_set("ads") { "src/bat/ads/internal/ad_targeting/processors/behavioral/bandits/bandit_feedback_info.h", "src/bat/ads/internal/ad_targeting/processors/behavioral/bandits/epsilon_greedy_bandit_processor.cc", "src/bat/ads/internal/ad_targeting/processors/behavioral/bandits/epsilon_greedy_bandit_processor.h", - "src/bat/ads/internal/ad_targeting/processors/behavioral/purchase_intent/purchase_intent_processor_values.h", "src/bat/ads/internal/ad_targeting/processors/behavioral/purchase_intent/purchase_intent_processor.cc", "src/bat/ads/internal/ad_targeting/processors/behavioral/purchase_intent/purchase_intent_processor.h", - "src/bat/ads/internal/ad_targeting/processors/contextual/text_classification/text_classification_processor_values.h", + "src/bat/ads/internal/ad_targeting/processors/behavioral/purchase_intent/purchase_intent_processor_values.h", "src/bat/ads/internal/ad_targeting/processors/contextual/text_classification/text_classification_processor.cc", "src/bat/ads/internal/ad_targeting/processors/contextual/text_classification/text_classification_processor.h", + "src/bat/ads/internal/ad_targeting/processors/contextual/text_classification/text_classification_processor_values.h", "src/bat/ads/internal/ad_targeting/processors/processor.h", "src/bat/ads/internal/ad_targeting/resources/behavioral/bandits/epsilon_greedy_bandit_resource.cc", "src/bat/ads/internal/ad_targeting/resources/behavioral/bandits/epsilon_greedy_bandit_resource.h", @@ -238,6 +245,9 @@ source_set("ads") { "src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.cc", "src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.h", "src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad_observer.h", + "src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.cc", + "src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.h", + "src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad_observer.h", "src/bat/ads/internal/ads_client_helper.cc", "src/bat/ads/internal/ads_client_helper.h", "src/bat/ads/internal/ads_history/ads_history.cc", @@ -270,6 +280,8 @@ source_set("ads") { "src/bat/ads/internal/bundle/creative_ad_notification_info.h", "src/bat/ads/internal/bundle/creative_new_tab_page_ad_info.cc", "src/bat/ads/internal/bundle/creative_new_tab_page_ad_info.h", + "src/bat/ads/internal/bundle/creative_promoted_content_ad_info.cc", + "src/bat/ads/internal/bundle/creative_promoted_content_ad_info.h", "src/bat/ads/internal/catalog/catalog.cc", "src/bat/ads/internal/catalog/catalog.h", "src/bat/ads/internal/catalog/catalog_ad_notification_payload_info.cc", @@ -282,6 +294,8 @@ source_set("ads") { "src/bat/ads/internal/catalog/catalog_creative_info.h", "src/bat/ads/internal/catalog/catalog_creative_new_tab_page_ad_info.cc", "src/bat/ads/internal/catalog/catalog_creative_new_tab_page_ad_info.h", + "src/bat/ads/internal/catalog/catalog_creative_promoted_content_ad_info.cc", + "src/bat/ads/internal/catalog/catalog_creative_promoted_content_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_daypart_info.cc", @@ -296,6 +310,8 @@ source_set("ads") { "src/bat/ads/internal/catalog/catalog_new_tab_page_ad_payload_info.h", "src/bat/ads/internal/catalog/catalog_os_info.cc", "src/bat/ads/internal/catalog/catalog_os_info.h", + "src/bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.cc", + "src/bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.h", "src/bat/ads/internal/catalog/catalog_segment_info.cc", "src/bat/ads/internal/catalog/catalog_segment_info.h", "src/bat/ads/internal/catalog/catalog_state.cc", @@ -358,6 +374,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/creative_promoted_content_ads_database_table.cc", + "src/bat/ads/internal/database/tables/creative_promoted_content_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", @@ -402,6 +420,8 @@ source_set("ads") { "src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap.h", "src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap.cc", "src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap.h", + "src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.cc", + "src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.h", "src/bat/ads/internal/frequency_capping/exclusion_rules/subdivision_targeting_frequency_cap.cc", "src/bat/ads/internal/frequency_capping/exclusion_rules/subdivision_targeting_frequency_cap.h", "src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap.cc", @@ -437,10 +457,16 @@ source_set("ads") { "src/bat/ads/internal/frequency_capping/permission_rules/permission_rule.h", "src/bat/ads/internal/frequency_capping/permission_rules/permission_rule_util.cc", "src/bat/ads/internal/frequency_capping/permission_rules/permission_rule_util.h", + "src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.cc", + "src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.h", + "src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.cc", + "src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.h", "src/bat/ads/internal/frequency_capping/permission_rules/unblinded_tokens_frequency_cap.cc", "src/bat/ads/internal/frequency_capping/permission_rules/unblinded_tokens_frequency_cap.h", "src/bat/ads/internal/frequency_capping/permission_rules/user_activity_frequency_cap.cc", "src/bat/ads/internal/frequency_capping/permission_rules/user_activity_frequency_cap.h", + "src/bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.cc", + "src/bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.h", "src/bat/ads/internal/json_helper.cc", "src/bat/ads/internal/json_helper.h", "src/bat/ads/internal/legacy_migration/legacy_migration_util.cc", @@ -532,6 +558,7 @@ source_set("ads") { "src/bat/ads/internal/user_activity/user_activity.h", "src/bat/ads/new_tab_page_ad_info.cc", "src/bat/ads/pref_names.cc", + "src/bat/ads/promoted_content_ad_info.cc", "src/bat/ads/statement_info.cc", "src/bat/ads/transaction_info.cc", ] diff --git a/vendor/bat-native-ads/data/resources/catalog-schema.json b/vendor/bat-native-ads/data/resources/catalog-schema.json index 4ab7f3cd873d..151dd6ccb527 100755 --- a/vendor/bat-native-ads/data/resources/catalog-schema.json +++ b/vendor/bat-native-ads/data/resources/catalog-schema.json @@ -283,6 +283,32 @@ }, "additionalProperties": false }, + { + "properties": { + "domain": { + "type": "string" + }, + "feed": { + "type": "string" + }, + "title": { + "type": "string" + }, + "category": { + "type": "string" + }, + "ogImages": { + "type": "boolean" + }, + "contentType": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false + }, { "properties": { "logo": { diff --git a/vendor/bat-native-ads/data/test/catalog.json b/vendor/bat-native-ads/data/test/catalog.json index b89da9a4cac4..57b3d91726d6 100644 --- a/vendor/bat-native-ads/data/test/catalog.json +++ b/vendor/bat-native-ads/data/test/catalog.json @@ -1,5 +1,5 @@ { - "version": 5, + "version": 6, "issuers": [ { "name": "confirmation", @@ -43,6 +43,24 @@ "title": "Test Ad 2 Campaign 1 Title", "targetUrl": "https://brave.com/2" } + }, + { + "creativeInstanceId": "75d4cbac-b661-4126-9ccb-7bbb6ee56ef3", + "type": { + "code": "promoted_content_all_v1", + "name": "promoted_content", + "platform": "all", + "version": 1 + }, + "payload": { + "feed": "https://brave.com/3", + "title": "Test Ad 3 Campaign 1 Title", + "domain": "Domain", + "category": "Category", + "ogImages": false, + "contentType": "Content Type", + "description": "Test Ad 3 Campaign 1 Body" + } } ], "segments": [ diff --git a/vendor/bat-native-ads/data/test/catalog_with_multiple_campaigns.json b/vendor/bat-native-ads/data/test/catalog_with_multiple_campaigns.json index 926c20d8d7e6..500453854eba 100644 --- a/vendor/bat-native-ads/data/test/catalog_with_multiple_campaigns.json +++ b/vendor/bat-native-ads/data/test/catalog_with_multiple_campaigns.json @@ -1,5 +1,5 @@ { - "version": 5, + "version": 6, "issuers": [ { "name": "confirmation", @@ -46,7 +46,7 @@ "logo": { "alt": "Test New Tab Page Ad Campaign 1", "imageUrl": "https://brave.com/1/test.jpg", - "companyName": "Brave 1", + "companyName": "New Tab Page 1", "destinationUrl": "https://brave.com/1/new_tab_page_ad" }, "wallpapers": [ @@ -66,6 +66,24 @@ } ] } + }, + { + "creativeInstanceId": "60001aa5-9368-45d2-81fc-e69887d278c5", + "type": { + "code": "promoted_content_all_v1", + "name": "promoted_content", + "platform": "all", + "version": 1 + }, + "payload": { + "feed": "https://brave.com/1/promoted_content_ad", + "title": "Promoted Content 1", + "domain": "Domain 1", + "category": "Category 1", + "ogImages": false, + "contentType": "Content Type 1", + "description": "Test Promoted Content Ad Campaign 1" + } } ], "segments": [ @@ -158,7 +176,7 @@ "logo": { "alt": "Test New Tab Page Ad Campaign 2", "imageUrl": "https://brave.com/2/test.jpg", - "companyName": "Brave 2", + "companyName": "New Tab Page 2", "destinationUrl": "https://brave.com/2/new_tab_page_ad" }, "wallpapers": [ @@ -178,6 +196,24 @@ } ] } + }, + { + "creativeInstanceId": "9f2f49ab-77d7-4e99-9428-472dc8e04f90", + "type": { + "code": "promoted_content_all_v1", + "name": "promoted_content", + "platform": "all", + "version": 1 + }, + "payload": { + "feed": "https://brave.com/2/promoted_content_ad", + "title": "Promoted Content 2", + "domain": "Domain 2", + "category": "Category 2", + "ogImages": true, + "contentType": "Content Type 2", + "description": "Test Promoted Content Ad Campaign 2" + } } ], "segments": [ diff --git a/vendor/bat-native-ads/data/test/catalog_with_single_campaign.json b/vendor/bat-native-ads/data/test/catalog_with_single_campaign.json index 993f227a5ef2..87b91c5bba6d 100644 --- a/vendor/bat-native-ads/data/test/catalog_with_single_campaign.json +++ b/vendor/bat-native-ads/data/test/catalog_with_single_campaign.json @@ -1,5 +1,5 @@ { - "version": 5, + "version": 6, "issuers": [ { "name": "confirmation", @@ -46,7 +46,7 @@ "logo": { "alt": "Test New Tab Page Ad Campaign 1", "imageUrl": "https://brave.com/1/test.jpg", - "companyName": "Brave 1", + "companyName": "New Tab Page 1", "destinationUrl": "https://brave.com/1/new_tab_page_ad" }, "wallpapers": [ @@ -66,6 +66,24 @@ } ] } + }, + { + "creativeInstanceId": "532943cb-b564-456f-9328-3eb7f7b79cb9", + "type": { + "code": "promoted_content_all_v1", + "name": "promoted_content", + "platform": "all", + "version": 1 + }, + "payload": { + "feed": "https://brave.com/3", + "title": "Promoted Content 1", + "domain": "Domain 1", + "category": "Category 1", + "ogImages": false, + "contentType": "Content Type 1", + "description": "Test Promoted Content Ad Campaign 1" + } } ], "segments": [ diff --git a/vendor/bat-native-ads/data/test/empty_catalog.json b/vendor/bat-native-ads/data/test/empty_catalog.json index 997016e0bb6a..ab9b94151f0f 100644 --- a/vendor/bat-native-ads/data/test/empty_catalog.json +++ b/vendor/bat-native-ads/data/test/empty_catalog.json @@ -1,5 +1,5 @@ { - "version": 5, + "version": 6, "issuers": [ { "name": "confirmation", diff --git a/vendor/bat-native-ads/include/bat/ads/ad_type.h b/vendor/bat-native-ads/include/bat/ads/ad_type.h index 6711baf0bdb8..d942c2e057cb 100644 --- a/vendor/bat-native-ads/include/bat/ads/ad_type.h +++ b/vendor/bat-native-ads/include/bat/ads/ad_type.h @@ -15,7 +15,8 @@ class AdType { enum Value { kUndefined, kAdNotification, - kNewTabPageAd + kNewTabPageAd, + kPromotedContentAd }; AdType() = default; diff --git a/vendor/bat-native-ads/include/bat/ads/ads.h b/vendor/bat-native-ads/include/bat/ads/ads.h index e618a4478299..128a4a8dd169 100644 --- a/vendor/bat-native-ads/include/bat/ads/ads.h +++ b/vendor/bat-native-ads/include/bat/ads/ads.h @@ -19,6 +19,7 @@ #include "bat/ads/category_content_info.h" #include "bat/ads/export.h" #include "bat/ads/mojom.h" +#include "bat/ads/promoted_content_ad_info.h" #include "bat/ads/result.h" #include "bat/ads/statement_info.h" @@ -163,10 +164,16 @@ class ADS_EXPORT Ads { // Should be called when a user views or clicks a new tab page ad virtual void OnNewTabPageAdEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type) = 0; + // Should be called when a user views or clicks a promoted content ad + virtual void OnPromotedContentAdEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type) = 0; + // Should be called to remove all cached history. The callback takes one // argument — |Result| should be set to |SUCCESS| if successful otherwise // should be set to |FAILED| diff --git a/vendor/bat-native-ads/include/bat/ads/mojom.h b/vendor/bat-native-ads/include/bat/ads/mojom.h index e27bfda73edc..128cb5b8ef82 100644 --- a/vendor/bat-native-ads/include/bat/ads/mojom.h +++ b/vendor/bat-native-ads/include/bat/ads/mojom.h @@ -21,6 +21,7 @@ using BuildChannelPtr = mojom::BraveAdsBuildChannelPtr; using AdNotificationEventType = mojom::BraveAdsAdNotificationEventType; using NewTabPageAdEventType = mojom::BraveAdsNewTabPageAdEventType; +using PromotedContentAdEventType = mojom::BraveAdsPromotedContentAdEventType; using UrlRequest = mojom::BraveAdsUrlRequest; using UrlRequestPtr = mojom::BraveAdsUrlRequestPtr; diff --git a/vendor/bat-native-ads/include/bat/ads/promoted_content_ad_info.h b/vendor/bat-native-ads/include/bat/ads/promoted_content_ad_info.h new file mode 100644 index 000000000000..eb493a525d2b --- /dev/null +++ b/vendor/bat-native-ads/include/bat/ads/promoted_content_ad_info.h @@ -0,0 +1,35 @@ +/* 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_PROMOTED_CONTENT_AD_INFO_H_ +#define BAT_ADS_PROMOTED_CONTENT_AD_INFO_H_ + +#include + +#include "bat/ads/ad_info.h" +#include "bat/ads/export.h" +#include "bat/ads/result.h" + +namespace ads { + +struct ADS_EXPORT PromotedContentAdInfo : AdInfo { + PromotedContentAdInfo(); + PromotedContentAdInfo( + const PromotedContentAdInfo& info); + ~PromotedContentAdInfo(); + + bool IsValid() const; + + std::string ToJson() const; + Result FromJson( + const std::string& json); + + std::string title; + std::string description; +}; + +} // namespace ads + +#endif // BAT_ADS_PROMOTED_CONTENT_AD_INFO_H_ diff --git a/vendor/bat-native-ads/include/bat/ads/public/interfaces/ads.mojom b/vendor/bat-native-ads/include/bat/ads/public/interfaces/ads.mojom index a0a98f66259a..73f7a6d92bb5 100644 --- a/vendor/bat-native-ads/include/bat/ads/public/interfaces/ads.mojom +++ b/vendor/bat-native-ads/include/bat/ads/public/interfaces/ads.mojom @@ -23,7 +23,8 @@ struct BraveAdsBuildChannel { enum BraveAdsAdType { kUndefined = 0, kAdNotification, - kNewTabPageAd + kNewTabPageAd, + kPromotedContentAd }; // If ad notification event types are added to the 7-day ads history you should @@ -42,6 +43,13 @@ enum BraveAdsNewTabPageAdEventType { kClicked }; +// If promoted content ad event types are added to the 7-day ads history you +// should update |kMaximumEntries| in |ads_history.h| +enum BraveAdsPromotedContentAdEventType { + kViewed = 0, + kClicked +}; + enum BraveAdsUrlRequestMethod { GET = 0, PUT, diff --git a/vendor/bat-native-ads/src/bat/ads/ad_type.cc b/vendor/bat-native-ads/src/bat/ads/ad_type.cc index 7d8bde7ba8e0..7b27a8eec9da 100644 --- a/vendor/bat-native-ads/src/bat/ads/ad_type.cc +++ b/vendor/bat-native-ads/src/bat/ads/ad_type.cc @@ -16,6 +16,7 @@ namespace { const char kUndefinedType[] = ""; const char kAdNotificationType[] = "ad_notification"; const char kNewTabPageAdType[] = "new_tab_page_ad"; +const char kPromotedContentAdType[] = "promoted_content_ad"; } // namespace @@ -27,6 +28,8 @@ AdType::AdType( value_ = kAdNotification; } else if (value == kNewTabPageAdType) { value_ = kNewTabPageAd; + } else if (value == kPromotedContentAdType) { + value_ = kPromotedContentAd; } else { NOTREACHED(); } @@ -49,6 +52,10 @@ AdType::operator std::string() const { case kNewTabPageAd: { return kNewTabPageAdType; } + + case kPromotedContentAd: { + return kPromotedContentAdType; + } } } diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_clicked.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_clicked.cc index 5d2cfe8022b3..a805dc1903a5 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_clicked.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_clicked.cc @@ -8,7 +8,6 @@ #include "bat/ads/confirmation_type.h" #include "bat/ads/internal/account/confirmations/confirmations.h" #include "bat/ads/internal/ad_events/ad_events.h" -#include "bat/ads/internal/ad_transfer/ad_transfer.h" #include "bat/ads/internal/ads_history/ads_history.h" #include "bat/ads/internal/logging.h" #include "bat/ads/new_tab_page_ad_info.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_viewed.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_viewed.cc index 2611a437fec4..90a22d24e409 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_viewed.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_viewed.cc @@ -5,8 +5,6 @@ #include "bat/ads/internal/ad_events/new_tab_page_ads/new_tab_page_ad_event_viewed.h" -#include - #include "bat/ads/confirmation_type.h" #include "bat/ads/internal/ad_events/ad_events.h" #include "bat/ads/internal/ads_history/ads_history.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.cc new file mode 100644 index 000000000000..2b93f5cecdcb --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.cc @@ -0,0 +1,40 @@ +/* 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/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.h" + +#include "bat/ads/confirmation_type.h" +#include "bat/ads/internal/ad_events/ad_events.h" +#include "bat/ads/internal/ads_history/ads_history.h" +#include "bat/ads/internal/logging.h" +#include "bat/ads/promoted_content_ad_info.h" + +namespace ads { +namespace promoted_content_ads { + +AdEventClicked::AdEventClicked() = default; + +AdEventClicked::~AdEventClicked() = default; + +void AdEventClicked::FireEvent( + const PromotedContentAdInfo& ad) { + BLOG(3, "Clicked promoted content ad with uuid " << ad.uuid + << " and creative instance id " << ad.creative_instance_id); + + LogAdEvent(ad, ConfirmationType::kClicked, []( + const Result result) { + if (result != Result::SUCCESS) { + BLOG(1, "Failed to log promoted content ad clicked event"); + return; + } + + BLOG(6, "Successfully logged promoted content ad clicked event"); + }); + + history::AddPromotedContentAd(ad, ConfirmationType::kClicked); +} + +} // namespace promoted_content_ads +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.h new file mode 100644 index 000000000000..d9f17dad2cf0 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.h @@ -0,0 +1,30 @@ +/* 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_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_CLICKED_H_ // NOLINT +#define BAT_ADS_INTERNAL_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_CLICKED_H_ // NOLINT + +#include "bat/ads/internal/ad_events/ad_event.h" + +namespace ads { + +struct PromotedContentAdInfo; + +namespace promoted_content_ads { + +class AdEventClicked : public AdEvent { + public: + AdEventClicked(); + + ~AdEventClicked() override; + + void FireEvent( + const PromotedContentAdInfo& ad) override; +}; + +} // namespace promoted_content_ads +} // namespace ads + +#endif // BAT_ADS_INTERNAL_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_CLICKED_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.cc new file mode 100644 index 000000000000..2acb90ac5887 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.cc @@ -0,0 +1,29 @@ +/* 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/ad_events/promoted_content_ads/promoted_content_ad_event_factory.h" + +#include "bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_clicked.h" +#include "bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.h" +#include "bat/ads/promoted_content_ad_info.h" + +namespace ads { +namespace promoted_content_ads { + +std::unique_ptr> AdEventFactory::Build( + const PromotedContentAdEventType event_type) { + switch (event_type) { + case PromotedContentAdEventType::kViewed: { + return std::make_unique(); + } + + case PromotedContentAdEventType::kClicked: { + return std::make_unique(); + } + } +} + +} // namespace promoted_content_ads +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.h new file mode 100644 index 000000000000..bd96f2d2ef0e --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.h @@ -0,0 +1,29 @@ +/* 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_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_FACTORY_H_ // NOLINT +#define BAT_ADS_INTERNAL_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_FACTORY_H_ // NOLINT + +#include + +#include "bat/ads/internal/ad_events/ad_event.h" +#include "bat/ads/mojom.h" + +namespace ads { + +struct PromotedContentAdInfo; + +namespace promoted_content_ads { + +class AdEventFactory { + public: + static std::unique_ptr> Build( + const PromotedContentAdEventType event_type); +}; + +} // namespace promoted_content_ads +} // namespace ads + +#endif // BAT_ADS_INTERNAL_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_FACTORY_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.cc new file mode 100644 index 000000000000..96aeca629aed --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.cc @@ -0,0 +1,40 @@ +/* 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/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.h" + +#include "bat/ads/confirmation_type.h" +#include "bat/ads/internal/ad_events/ad_events.h" +#include "bat/ads/internal/ads_history/ads_history.h" +#include "bat/ads/internal/logging.h" +#include "bat/ads/promoted_content_ad_info.h" + +namespace ads { +namespace promoted_content_ads { + +AdEventViewed::AdEventViewed() = default; + +AdEventViewed::~AdEventViewed() = default; + +void AdEventViewed::FireEvent( + const PromotedContentAdInfo& ad) { + BLOG(3, "Viewed promoted content ad with uuid " << ad.uuid + << " and creative instance id " << ad.creative_instance_id); + + LogAdEvent(ad, ConfirmationType::kViewed, []( + const Result result) { + if (result != Result::SUCCESS) { + BLOG(1, "Failed to log promoted content ad viewed event"); + return; + } + + BLOG(6, "Successfully logged promoted content ad viewed event"); + }); + + history::AddPromotedContentAd(ad, ConfirmationType::kViewed); +} + +} // namespace promoted_content_ads +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.h new file mode 100644 index 000000000000..af785231fbde --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_viewed.h @@ -0,0 +1,30 @@ +/* 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_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_VIEWED_H_ // NOLINT +#define BAT_ADS_INTERNAL_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_VIEWED_H_ // NOLINT + +#include "bat/ads/internal/ad_events/ad_event.h" + +namespace ads { + +struct PromotedContentAdInfo; + +namespace promoted_content_ads { + +class AdEventViewed : public AdEvent { + public: + AdEventViewed(); + + ~AdEventViewed() override; + + void FireEvent( + const PromotedContentAdInfo& ad) override; +}; + +} // namespace promoted_content_ads +} // namespace ads + +#endif // BAT_ADS_INTERNAL_AD_EVENTS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_EVENT_VIEWED_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_server/ad_server.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_server/ad_server.cc index 2bc3a083f416..82722d62479d 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_server/ad_server.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_server/ad_server.cc @@ -62,7 +62,7 @@ void AdServer::Fetch() { DCHECK(!is_processing_); BLOG(1, "Get catalog"); - BLOG(2, "GET /v5/catalog"); + BLOG(2, "GET /v6/catalog"); is_processing_ = true; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_server/get_catalog_url_request_builder.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_server/get_catalog_url_request_builder.cc index dd83931e181c..790e1de73133 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_server/get_catalog_url_request_builder.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_server/get_catalog_url_request_builder.cc @@ -14,7 +14,7 @@ GetCatalogUrlRequestBuilder::GetCatalogUrlRequestBuilder() = default; GetCatalogUrlRequestBuilder::~GetCatalogUrlRequestBuilder() = default; -// GET /v5/catalog +// GET /v6/catalog UrlRequestPtr GetCatalogUrlRequestBuilder::Build() { UrlRequestPtr url_request = UrlRequest::New(); @@ -27,7 +27,7 @@ UrlRequestPtr GetCatalogUrlRequestBuilder::Build() { /////////////////////////////////////////////////////////////////////////////// std::string GetCatalogUrlRequestBuilder::BuildUrl() const { - return base::StringPrintf("%s/v5/catalog", server::GetHost().c_str()); + return base::StringPrintf("%s/v6/catalog", server::GetHost().c_str()); } } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_transfer/ad_transfer_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_transfer/ad_transfer_unittest.cc index f12a29920e4d..095093bc4eb1 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_transfer/ad_transfer_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_transfer/ad_transfer_unittest.cc @@ -64,7 +64,7 @@ class BatAdsAdTransferTest TEST_F(BatAdsAdTransferTest, DoNotTransferAdIfUrlIsMissingHTTPOrHTTPSScheme) { // Arrange - const AdInfo ad = GetAdForType(AdType::kAdNotification); + const AdInfo ad = GetAdForType(AdType::kPromotedContentAd); ad_transfer_->set_last_clicked_ad(ad); TabManager::Get()->OnUpdated(1, "https://brave.com", /* is_visible */ true, @@ -117,7 +117,7 @@ TEST_F(BatAdsAdTransferTest, TEST_F(BatAdsAdTransferTest, TransferAdIfAnotherAdIsAlreadyTransferring) { // Arrange - const AdInfo ad = GetAdForType(AdType::kAdNotification); + const AdInfo ad = GetAdForType(AdType::kPromotedContentAd); ad_transfer_->set_last_clicked_ad(ad); TabManager::Get()->OnUpdated(1, "https://foobar.com", /* is_visible */ true, diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.cc b/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.cc index 6c03f9ac75a9..d871c90af6bc 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.cc @@ -54,16 +54,14 @@ void NewTabPageAd::RemoveObserver( } void NewTabPageAd::FireEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type) { - if (wallpaper_id.empty() || creative_instance_id.empty()) { - BLOG(1, "Failed to fire new tab page ad event for wallpaper id " - << wallpaper_id << " and creative instance id " - << creative_instance_id); + if (uuid.empty() || creative_instance_id.empty()) { + BLOG(1, "Failed to fire new tab page ad event for uuid " << uuid + << " and creative instance id " << creative_instance_id); - NotifyNewTabPageAdEventFailed(wallpaper_id, - creative_instance_id, event_type); + NotifyNewTabPageAdEventFailed(uuid, creative_instance_id, event_type); return; } @@ -74,18 +72,17 @@ void NewTabPageAd::FireEvent( const std::string& creative_instance_id, const CreativeNewTabPageAdInfo& creative_new_tab_page_ad) { if (result != SUCCESS) { - BLOG(1, "Failed to fire new tab page ad event for wallpaper id"); + BLOG(1, "Failed to fire new tab page ad event for uuid"); - NotifyNewTabPageAdEventFailed(wallpaper_id, - creative_instance_id, event_type); + NotifyNewTabPageAdEventFailed(uuid, creative_instance_id, event_type); return; } const NewTabPageAdInfo ad = - CreateNewTabPageAd(wallpaper_id, creative_new_tab_page_ad); + CreateNewTabPageAd(uuid, creative_new_tab_page_ad); - FireEvent(ad, wallpaper_id, creative_instance_id, event_type); + FireEvent(ad, uuid, creative_instance_id, event_type); }); } @@ -109,7 +106,7 @@ bool NewTabPageAd::ShouldFireEvent( void NewTabPageAd::FireEvent( const NewTabPageAdInfo& ad, - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type) { database::table::AdEvents database_table; @@ -119,8 +116,7 @@ void NewTabPageAd::FireEvent( if (result != Result::SUCCESS) { BLOG(1, "New tab page ad: Failed to get ad events"); - NotifyNewTabPageAdEventFailed(wallpaper_id, - creative_instance_id, event_type); + NotifyNewTabPageAdEventFailed(uuid, creative_instance_id, event_type); return; } @@ -129,8 +125,7 @@ void NewTabPageAd::FireEvent( !ShouldFireEvent(ad, ad_events)) { BLOG(1, "New tab page ad: Not allowed"); - NotifyNewTabPageAdEventFailed(wallpaper_id, - creative_instance_id, event_type); + NotifyNewTabPageAdEventFailed(uuid, creative_instance_id, event_type); return; } @@ -173,12 +168,11 @@ void NewTabPageAd::NotifyNewTabPageAdClicked( } void NewTabPageAd::NotifyNewTabPageAdEventFailed( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type) { for (NewTabPageAdObserver& observer : observers_) { - observer.OnNewTabPageAdEventFailed(wallpaper_id, - creative_instance_id, event_type); + observer.OnNewTabPageAdEventFailed(uuid, creative_instance_id, event_type); } } diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.h b/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.h index f26ead5cb7a4..81fc3fa29c44 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.h @@ -29,9 +29,9 @@ class NewTabPageAd NewTabPageAdObserver* observer); void FireEvent( - const std::string& wallpaper_id, - const std::string& creative_instance_id, - const NewTabPageAdEventType event_type); + const std::string& uuid, + const std::string& creative_instance_id, + const NewTabPageAdEventType event_type); private: base::ObserverList observers_; @@ -42,7 +42,7 @@ class NewTabPageAd void FireEvent( const NewTabPageAdInfo& ad, - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type); @@ -56,7 +56,7 @@ class NewTabPageAd const NewTabPageAdInfo& ad); void NotifyNewTabPageAdEventFailed( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type); }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad_observer.h b/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad_observer.h index 0b1a6fa826d8..2ef433f0343c 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad_observer.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad_observer.h @@ -27,7 +27,7 @@ class NewTabPageAdObserver : public base::CheckedObserver { // Invoked when a new tab page ad event fails virtual void OnNewTabPageAdEventFailed( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type) {} diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.cc b/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.cc new file mode 100644 index 000000000000..f10641a43e69 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.cc @@ -0,0 +1,184 @@ +/* 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/ads/promoted_content_ads/promoted_content_ad.h" + +#include "bat/ads/internal/ad_events/promoted_content_ads/promoted_content_ad_event_factory.h" +#include "bat/ads/internal/bundle/creative_promoted_content_ad_info.h" +#include "bat/ads/internal/database/tables/ad_events_database_table.h" +#include "bat/ads/internal/database/tables/creative_promoted_content_ads_database_table.h" +#include "bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.h" +#include "bat/ads/internal/logging.h" +#include "bat/ads/promoted_content_ad_info.h" + +namespace ads { + +namespace { + +PromotedContentAdInfo CreatePromotedContentAd( + const std::string& uuid, + const CreativePromotedContentAdInfo& ad) { + PromotedContentAdInfo promoted_content_ad; + + promoted_content_ad.type = AdType::kPromotedContentAd; + promoted_content_ad.uuid = uuid; + promoted_content_ad.creative_instance_id = ad.creative_instance_id; + promoted_content_ad.creative_set_id = ad.creative_set_id; + promoted_content_ad.campaign_id = ad.campaign_id; + promoted_content_ad.segment = ad.segment; + promoted_content_ad.target_url = ad.target_url; + promoted_content_ad.title = ad.title; + promoted_content_ad.description = ad.description; + + return promoted_content_ad; +} + +} // namespace + +PromotedContentAd::PromotedContentAd() = default; + +PromotedContentAd::~PromotedContentAd() = default; + +void PromotedContentAd::AddObserver( + PromotedContentAdObserver* observer) { + DCHECK(observer); + observers_.AddObserver(observer); +} + +void PromotedContentAd::RemoveObserver( + PromotedContentAdObserver* observer) { + DCHECK(observer); + observers_.RemoveObserver(observer); +} + +void PromotedContentAd::FireEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type) { + if (uuid.empty() || creative_instance_id.empty()) { + BLOG(1, "Failed to fire promoted content ad event for uuid " << uuid + << " and creative instance id " << creative_instance_id); + + NotifyPromotedContentAdEventFailed(uuid, creative_instance_id, event_type); + + return; + } + + database::table::CreativePromotedContentAds database_table; + database_table.GetForCreativeInstanceId(creative_instance_id, [=]( + const Result result, + const std::string& creative_instance_id, + const CreativePromotedContentAdInfo& creative_promoted_content_ad) { + if (result != SUCCESS) { + BLOG(1, "Failed to fire promoted content ad event for uuid"); + + NotifyPromotedContentAdEventFailed(uuid, creative_instance_id, + event_type); + + return; + } + + const PromotedContentAdInfo ad = + CreatePromotedContentAd(uuid, creative_promoted_content_ad); + + FireEvent(ad, uuid, creative_instance_id, event_type); + }); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool PromotedContentAd::ShouldFireEvent( + const PromotedContentAdInfo& ad, + const AdEventList& ad_events) { + promoted_content_ads::FrequencyCapping frequency_capping(ad_events); + + if (!frequency_capping.IsAdAllowed()) { + return false; + } + + if (frequency_capping.ShouldExcludeAd(ad)) { + return false; + } + + return true; +} + +void PromotedContentAd::FireEvent( + const PromotedContentAdInfo& ad, + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type) { + database::table::AdEvents database_table; + database_table.GetAll([=]( + const Result result, + const AdEventList& ad_events) { + if (result != Result::SUCCESS) { + BLOG(1, "Promoted content ad: Failed to get ad events"); + + NotifyPromotedContentAdEventFailed(uuid, creative_instance_id, + event_type); + + return; + } + + if (event_type == PromotedContentAdEventType::kViewed && + !ShouldFireEvent(ad, ad_events)) { + BLOG(1, "Promoted content ad: Not allowed"); + + NotifyPromotedContentAdEventFailed(uuid, creative_instance_id, + event_type); + + return; + } + + const auto ad_event = + promoted_content_ads::AdEventFactory::Build(event_type); + ad_event->FireEvent(ad); + + NotifyPromotedContentAdEvent(ad, event_type); + }); +} + +void PromotedContentAd::NotifyPromotedContentAdEvent( + const PromotedContentAdInfo& ad, + const PromotedContentAdEventType event_type) { + switch (event_type) { + case PromotedContentAdEventType::kViewed: { + NotifyPromotedContentAdViewed(ad); + break; + } + + case PromotedContentAdEventType::kClicked: { + NotifyPromotedContentAdClicked(ad); + break; + } + } +} + +void PromotedContentAd::NotifyPromotedContentAdViewed( + const PromotedContentAdInfo& ad) { + for (PromotedContentAdObserver& observer : observers_) { + observer.OnPromotedContentAdViewed(ad); + } +} + +void PromotedContentAd::NotifyPromotedContentAdClicked( + const PromotedContentAdInfo& ad) { + for (PromotedContentAdObserver& observer : observers_) { + observer.OnPromotedContentAdClicked(ad); + } +} + +void PromotedContentAd::NotifyPromotedContentAdEventFailed( + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type) { + for (PromotedContentAdObserver& observer : observers_) { + observer.OnPromotedContentAdEventFailed(uuid, creative_instance_id, + event_type); + } +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.h b/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.h new file mode 100644 index 000000000000..faabd769d719 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.h @@ -0,0 +1,66 @@ +/* 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_ADS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_H_ +#define BAT_ADS_INTERNAL_ADS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_H_ + +#include + +#include "bat/ads/internal/ad_events/ad_event_info.h" +#include "bat/ads/internal/ads/promoted_content_ads/promoted_content_ad_observer.h" +#include "bat/ads/mojom.h" + +namespace ads { + +struct PromotedContentAdInfo; + +class PromotedContentAd + : public PromotedContentAdObserver { + public: + PromotedContentAd(); + + ~PromotedContentAd() override; + + void AddObserver( + PromotedContentAdObserver* observer); + void RemoveObserver( + PromotedContentAdObserver* observer); + + void FireEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type); + + private: + base::ObserverList observers_; + + bool ShouldFireEvent( + const PromotedContentAdInfo& ad, + const AdEventList& ad_events); + + void FireEvent( + const PromotedContentAdInfo& ad, + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type); + + void NotifyPromotedContentAdEvent( + const PromotedContentAdInfo& ad, + const PromotedContentAdEventType event_type); + + void NotifyPromotedContentAdViewed( + const PromotedContentAdInfo& ad); + void NotifyPromotedContentAdClicked( + const PromotedContentAdInfo& ad); + + void NotifyPromotedContentAdEventFailed( + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type); +}; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_ADS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad_observer.h b/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad_observer.h new file mode 100644 index 000000000000..1491549ad739 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads/promoted_content_ads/promoted_content_ad_observer.h @@ -0,0 +1,40 @@ +/* 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_ADS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_OBSERVER_H_ // NOLINT +#define BAT_ADS_INTERNAL_ADS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_OBSERVER_H_ // NOLINT + +#include + +#include "base/observer_list.h" +#include "bat/ads/mojom.h" + +namespace ads { + +struct PromotedContentAdInfo; + +class PromotedContentAdObserver : public base::CheckedObserver { + public: + // Invoked when a promoted content ad is viewed + virtual void OnPromotedContentAdViewed( + const PromotedContentAdInfo& ad) {} + + // Invoked when a promoted content ad is clicked + virtual void OnPromotedContentAdClicked( + const PromotedContentAdInfo& ad) {} + + // Invoked when a promoted content ad event fails + virtual void OnPromotedContentAdEventFailed( + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type) {} + + protected: + ~PromotedContentAdObserver() override = default; +}; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_ADS_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_AD_OBSERVER_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history.cc b/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history.cc index d6ae46d3a8fb..72043a59dfb3 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history.cc @@ -18,6 +18,7 @@ #include "bat/ads/internal/logging.h" #include "bat/ads/internal/url_util.h" #include "bat/ads/new_tab_page_ad_info.h" +#include "bat/ads/promoted_content_ad_info.h" namespace ads { namespace history { @@ -97,5 +98,27 @@ void AddNewTabPageAd( Client::Get()->AppendAdHistoryToAdsHistory(ad_history); } +void AddPromotedContentAd( + const PromotedContentAdInfo& ad, + const ConfirmationType& confirmation_type) { + AdHistoryInfo ad_history; + + ad_history.timestamp_in_seconds = + static_cast(base::Time::Now().ToDoubleT()); + ad_history.ad_content.type = ad.type; + ad_history.ad_content.uuid = ad.uuid; + ad_history.ad_content.creative_instance_id = ad.creative_instance_id; + ad_history.ad_content.creative_set_id = ad.creative_set_id; + ad_history.ad_content.campaign_id = ad.campaign_id; + ad_history.ad_content.brand = ad.title; + ad_history.ad_content.brand_info = ad.description; + ad_history.ad_content.brand_display_url = GetHostFromUrl(ad.target_url); + ad_history.ad_content.brand_url = ad.target_url; + ad_history.ad_content.ad_action = confirmation_type; + ad_history.category_content.category = ad.segment; + + Client::Get()->AppendAdHistoryToAdsHistory(ad_history); +} + } // namespace history } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history.h b/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history.h index c63d0c9f3e12..2b4897d8ad22 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history.h @@ -11,12 +11,14 @@ #include "bat/ads/ads_history_info.h" #include "bat/ads/internal/frequency_capping/permission_rules/ads_per_day_frequency_cap.h" #include "bat/ads/internal/frequency_capping/permission_rules/new_tab_page_ads_per_day_frequency_cap.h" +#include "bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.h" namespace ads { class ConfirmationType; struct AdNotificationInfo; struct NewTabPageAdInfo; +struct PromotedContentAdInfo; namespace history { @@ -25,8 +27,11 @@ namespace history { // confirmation types (viewed and either clicked or dismissed) and // |kNewTabPageAdsPerDayFrequencyCap| new tab page ads per day with 2 // confirmation types (viewed and clicked) +// |kPromotedContentAdsPerDayFrequencyCap| promoted content ads per day with 2 +// confirmation types (viewed and clicked) const size_t kMaximumEntries = 7 * ((kAdNotificationsPerDayFrequencyCap * 2) + - (kNewTabPageAdsPerDayFrequencyCap * 2)); + (kNewTabPageAdsPerDayFrequencyCap * 2) + + (kPromotedContentAdsPerDayFrequencyCap * 2)); AdsHistoryInfo Get( const AdsHistoryInfo::FilterType filter_type, @@ -42,6 +47,10 @@ void AddNewTabPageAd( const NewTabPageAdInfo& ad, const ConfirmationType& confirmation_type); +void AddPromotedContentAd( + const PromotedContentAdInfo& ad, + const ConfirmationType& confirmation_type); + } // namespace history } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history_unittest.cc index 471fbc5378e5..f2978592ccde 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_history/ads_history_unittest.cc @@ -11,6 +11,7 @@ #include "bat/ads/internal/unittest_base.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/new_tab_page_ad_info.h" +#include "bat/ads/promoted_content_ad_info.h" // npm run test -- brave_unit_tests --filter=BatAds* @@ -107,6 +108,104 @@ TEST_F(BatAdsAdsHistoryTest, ASSERT_EQ(history::kMaximumEntries, history.size()); } +TEST_F(BatAdsAdsHistoryTest, + AddPromotedContentAdToEmptyHistory) { + // Arrange + PromotedContentAdInfo ad; + + // Act + history::AddPromotedContentAd(ad, ConfirmationType::kViewed); + + // Assert + const std::deque history = Client::Get()->GetAdsHistory(); + ASSERT_EQ(1UL, history.size()); +} + +TEST_F(BatAdsAdsHistoryTest, + AddPromotedContentAdsToHistory) { + // Arrange + PromotedContentAdInfo ad; + + // Act + history::AddPromotedContentAd(ad, ConfirmationType::kViewed); + history::AddPromotedContentAd(ad, ConfirmationType::kClicked); + + // Assert + const std::deque history = Client::Get()->GetAdsHistory(); + ASSERT_EQ(2UL, history.size()); +} + +TEST_F(BatAdsAdsHistoryTest, + HistoryRespectsMaximumSizeForPromotedContentAds) { + // Arrange + PromotedContentAdInfo ad; + + // Act + for (size_t i = 0; i < history::kMaximumEntries + 1; i++) { + history::AddPromotedContentAd(ad, ConfirmationType::kViewed); + } + + // Assert + const std::deque history = Client::Get()->GetAdsHistory(); + ASSERT_EQ(history::kMaximumEntries, history.size()); +} + +TEST_F(BatAdsAdsHistoryTest, + AddMultipleAdTypesToHistory) { + // Arrange + + // Act + AdNotificationInfo ad_notification; + history::AddAdNotification(ad_notification, ConfirmationType::kViewed); + + NewTabPageAdInfo new_tab_page_ad; + history::AddNewTabPageAd(new_tab_page_ad, ConfirmationType::kViewed); + + PromotedContentAdInfo promoted_content_ad; + history::AddPromotedContentAd(promoted_content_ad, ConfirmationType::kViewed); + + // Assert + const std::deque history = Client::Get()->GetAdsHistory(); + ASSERT_EQ(3UL, history.size()); +} + +TEST_F(BatAdsAdsHistoryTest, + HistoryRespectsMaximumSizeForMultipleAdTypes) { + // Arrange + + // Act + for (size_t i = 0; i < history::kMaximumEntries + 1; i++) { + switch (i % 3) { + case 0: { + AdNotificationInfo ad_notification; + history::AddAdNotification(ad_notification, ConfirmationType::kViewed); + break; + } + + case 1: { + NewTabPageAdInfo new_tab_page_ad; + history::AddNewTabPageAd(new_tab_page_ad, ConfirmationType::kViewed); + break; + } + + case 2: { + PromotedContentAdInfo promoted_content_ad; + history::AddPromotedContentAd(promoted_content_ad, + ConfirmationType::kViewed); + break; + } + } + } + + // Assert + const std::deque history = Client::Get()->GetAdsHistory(); + ASSERT_EQ(history::kMaximumEntries, history.size()); +} + + + + + TEST_F(BatAdsAdsHistoryTest, MaximumHistoryEntries) { // Arrange @@ -114,7 +213,7 @@ TEST_F(BatAdsAdsHistoryTest, // Act // Assert - ASSERT_EQ(840UL, history::kMaximumEntries); + ASSERT_EQ(1120UL, history::kMaximumEntries); } } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_history/filters/ads_history_confirmation_filter_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ads_history/filters/ads_history_confirmation_filter_unittest.cc index 676a1129d307..a5d5a0fea73b 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_history/filters/ads_history_confirmation_filter_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_history/filters/ads_history_confirmation_filter_unittest.cc @@ -107,7 +107,7 @@ TEST(BatAdsHistoryConfirmationFilterTest, AdHistoryInfo ad4; // Unsupported ad4.ad_content.uuid = "a86a11d7-674c-494e-844d-f62417c2357b"; - ad4.ad_content.type = AdType::kNewTabPageAd; + ad4.ad_content.type = AdType::kPromotedContentAd; ad4.ad_content.creative_instance_id = "47c73793-d1c1-4fdb-8530-4ae478c79783"; ad4.ad_content.ad_action = ConfirmationType::kDownvoted; @@ -125,7 +125,7 @@ TEST(BatAdsHistoryConfirmationFilterTest, AdHistoryInfo ad7; // Dismiss ad7.ad_content.uuid = "1ec4f1ba-4255-4ecf-8701-8e550744cdf8"; - ad7.ad_content.type = AdType::kNewTabPageAd; + ad7.ad_content.type = AdType::kPromotedContentAd; ad7.ad_content.creative_instance_id = "d5d47c90-5c6b-4aa2-bd05-582ff6e4a03e"; ad7.ad_content.ad_action = ConfirmationType::kDismissed; 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 9eb171e359f4..502dd850d362 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 @@ -32,6 +32,7 @@ #include "bat/ads/internal/ads/ad_notifications/ad_notification.h" #include "bat/ads/internal/ads/ad_notifications/ad_notifications.h" #include "bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad.h" +#include "bat/ads/internal/ads/promoted_content_ads/promoted_content_ad.h" #include "bat/ads/internal/ads_client_helper.h" #include "bat/ads/internal/ads_history/ads_history.h" #include "bat/ads/internal/catalog/catalog.h" @@ -51,6 +52,7 @@ #include "bat/ads/internal/user_activity/user_activity.h" #include "bat/ads/new_tab_page_ad_info.h" #include "bat/ads/pref_names.h" +#include "bat/ads/promoted_content_ad_info.h" #include "bat/ads/statement_info.h" namespace ads { @@ -73,6 +75,7 @@ AdsImpl::~AdsImpl() { ad_transfer_->RemoveObserver(this); conversions_->RemoveObserver(this); new_tab_page_ad_->RemoveObserver(this); + promoted_content_ad_->RemoveObserver(this); } void AdsImpl::set_for_testing( @@ -269,10 +272,17 @@ void AdsImpl::OnAdNotificationEvent( } void AdsImpl::OnNewTabPageAdEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type) { - new_tab_page_ad_->FireEvent(wallpaper_id, creative_instance_id, event_type); + new_tab_page_ad_->FireEvent(uuid, creative_instance_id, event_type); +} + +void AdsImpl::OnPromotedContentAdEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type) { + promoted_content_ad_->FireEvent(uuid, creative_instance_id, event_type); } void AdsImpl::RemoveAllHistory( @@ -415,6 +425,9 @@ void AdsImpl::set( ad_transfer_ = std::make_unique(); ad_transfer_->AddObserver(this); + promoted_content_ad_ = std::make_unique(); + promoted_content_ad_->AddObserver(this); + client_ = std::make_unique(); conversions_ = std::make_unique(); @@ -572,6 +585,14 @@ void AdsImpl::OnTransactionsChanged() { AdsClientHelper::Get()->OnAdRewardsChanged(); } +void AdsImpl::OnCatalogUpdated( + const Catalog& catalog) { + account_->SetCatalogIssuers(catalog.GetIssuers()); + account_->TopUpUnblindedTokens(); + + epsilon_greedy_bandit_resource_->LoadFromDatabase(); +} + void AdsImpl::OnAdNotificationViewed( const AdNotificationInfo& ad) { account_->Deposit(ad.creative_instance_id, ConfirmationType::kViewed); @@ -601,34 +622,38 @@ void AdsImpl::OnAdNotificationTimedOut( AdNotificationEventType::kTimedOut}); } -void AdsImpl::OnCatalogUpdated( - const Catalog& catalog) { - account_->SetCatalogIssuers(catalog.GetIssuers()); - account_->TopUpUnblindedTokens(); - - epsilon_greedy_bandit_resource_->LoadFromDatabase(); +void AdsImpl::OnNewTabPageAdViewed( + const NewTabPageAdInfo& ad) { + account_->Deposit(ad.creative_instance_id, ConfirmationType::kViewed); } -void AdsImpl::OnAdTransfer( - const AdInfo& ad) { - account_->Deposit(ad.creative_instance_id, ConfirmationType::kTransferred); -} +void AdsImpl::OnNewTabPageAdClicked( + const NewTabPageAdInfo& ad) { + ad_transfer_->set_last_clicked_ad(ad); -void AdsImpl::OnConversion( - const std::string& creative_instance_id) { - account_->Deposit(creative_instance_id, ConfirmationType::kConversion); + account_->Deposit(ad.creative_instance_id, ConfirmationType::kClicked); } -void AdsImpl::OnNewTabPageAdViewed( - const NewTabPageAdInfo& ad) { +void AdsImpl::OnPromotedContentAdViewed( + const PromotedContentAdInfo& ad) { account_->Deposit(ad.creative_instance_id, ConfirmationType::kViewed); } -void AdsImpl::OnNewTabPageAdClicked( - const NewTabPageAdInfo& ad) { +void AdsImpl::OnPromotedContentAdClicked( + const PromotedContentAdInfo& ad) { ad_transfer_->set_last_clicked_ad(ad); account_->Deposit(ad.creative_instance_id, ConfirmationType::kClicked); } +void AdsImpl::OnAdTransfer( + const AdInfo& ad) { + account_->Deposit(ad.creative_instance_id, ConfirmationType::kTransferred); +} + +void AdsImpl::OnConversion( + const std::string& creative_instance_id) { + account_->Deposit(creative_instance_id, ConfirmationType::kConversion); +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h b/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h index 2333a3a86acd..3838508381aa 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h @@ -18,6 +18,7 @@ #include "bat/ads/internal/ad_transfer/ad_transfer_observer.h" #include "bat/ads/internal/ads/ad_notifications/ad_notification_observer.h" #include "bat/ads/internal/ads/new_tab_page_ads/new_tab_page_ad_observer.h" +#include "bat/ads/internal/ads/promoted_content_ads/promoted_content_ad_observer.h" #include "bat/ads/internal/conversions/conversions_observer.h" #include "bat/ads/internal/privacy/tokens/token_generator.h" #include "bat/ads/internal/privacy/tokens/token_generator_interface.h" @@ -67,12 +68,14 @@ class Client; class ConfirmationsState; class Conversions; class NewTabPageAd; +class PromotedContentAd; class TabManager; class UserActivity; struct AdInfo; struct AdNotificationInfo; struct AdsHistoryInfo; struct NewTabPageAdInfo; +struct PromotedContentAdInfo; class AdsImpl : public Ads, @@ -81,7 +84,8 @@ class AdsImpl public AdServerObserver, public AdTransferObserver, public ConversionsObserver, - public NewTabPageAdObserver { + public NewTabPageAdObserver, + public PromotedContentAdObserver { public: AdsImpl( AdsClient* ads_client); @@ -149,10 +153,15 @@ class AdsImpl const AdNotificationEventType event_type) override; void OnNewTabPageAdEvent( - const std::string& wallpaper_id, + const std::string& uuid, const std::string& creative_instance_id, const NewTabPageAdEventType event_type) override; + void OnPromotedContentAdEvent( + const std::string& uuid, + const std::string& creative_instance_id, + const PromotedContentAdEventType event_type) override; + void RemoveAllHistory( RemoveAllHistoryCallback callback) override; @@ -220,6 +229,7 @@ class AdsImpl std::unique_ptr conversions_; std::unique_ptr database_; std::unique_ptr new_tab_page_ad_; + std::unique_ptr promoted_content_ad_; std::unique_ptr tab_manager_; std::unique_ptr user_activity_; @@ -253,6 +263,10 @@ class AdsImpl void OnAdRewardsChanged() override; void OnTransactionsChanged() override; + // AdServerObserver implementation + void OnCatalogUpdated( + const Catalog& catalog) override; + // AdNotificationObserver implementation void OnAdNotificationViewed( const AdNotificationInfo& ad) override; @@ -263,9 +277,17 @@ class AdsImpl void OnAdNotificationTimedOut( const AdNotificationInfo& ad) override; - // AdServerObserver implementation - void OnCatalogUpdated( - const Catalog& catalog) override; + // NewTabPageAdObserver implementation + void OnNewTabPageAdViewed( + const NewTabPageAdInfo& ad) override; + void OnNewTabPageAdClicked( + const NewTabPageAdInfo& ad) override; + + // PromotedContentAdObserver implementation + void OnPromotedContentAdViewed( + const PromotedContentAdInfo& ad) override; + void OnPromotedContentAdClicked( + const PromotedContentAdInfo& ad) override; // AdTransferObserver implementation void OnAdTransfer( @@ -274,12 +296,6 @@ class AdsImpl // ConversionsObserver implementation void OnConversion( const std::string& creative_instance_id) override; - - // NewTabPageAdObserver implementation - void OnNewTabPageAdViewed( - const NewTabPageAdInfo& ad) override; - void OnNewTabPageAdClicked( - const NewTabPageAdInfo& ad) override; }; } // namespace ads 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 c77d93ed1bd1..b9162d99d5dc 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 @@ -21,6 +21,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/creative_promoted_content_ads_database_table.h" #include "bat/ads/internal/database/tables/geo_targets_database_table.h" #include "bat/ads/internal/database/tables/segments_database_table.h" #include "bat/ads/internal/logging.h" @@ -68,6 +69,8 @@ void Bundle::BuildFromCatalog( SaveCreativeNewTabPageAds(bundle_state.creative_new_tab_page_ads); + SaveCreativePromotedContentAds(bundle_state.creative_promoted_content_ads); + PurgeExpiredConversions(); SaveConversions(bundle_state.conversions); } @@ -78,6 +81,7 @@ BundleState Bundle::FromCatalog( const Catalog& catalog) const { CreativeAdNotificationList creative_ad_notifications; CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativePromotedContentAdList creative_promoted_content_ads; ConversionList conversions; // Campaigns @@ -273,6 +277,88 @@ BundleState Bundle::FromCatalog( } } + // Promoted content ad creatives + for (const auto& creative : creative_set.creative_promoted_content_ads) { + if (!DoesOsSupportCreativeSet(creative_set)) { + const std::string platform_name = + PlatformHelper::GetInstance()->GetPlatformName(); + + BLOG(1, "Creative set id " << creative_set.creative_set_id + << " does not support " << platform_name); + + continue; + } + + CreativePromotedContentAdInfo info; + info.creative_instance_id = creative.creative_instance_id; + info.creative_set_id = creative_set.creative_set_id; + info.campaign_id = campaign.campaign_id; + + base::Time start_at_time; + if (base::Time::FromUTCString(campaign.start_at.c_str(), + &start_at_time)) { + info.start_at_timestamp = + static_cast(start_at_time.ToDoubleT()); + } else { + info.start_at_timestamp = std::numeric_limits::min(); + + BLOG(1, "Creative set id " << creative_set.creative_set_id + << " has an invalid startAt timestamp"); + } + + base::Time end_at_time; + if (base::Time::FromUTCString(campaign.end_at.c_str(), + &end_at_time)) { + info.end_at_timestamp = + static_cast(end_at_time.ToDoubleT()); + } else { + info.end_at_timestamp = std::numeric_limits::max(); + + BLOG(1, "Creative set id " << creative_set.creative_set_id + << " has an invalid endAt timestamp"); + } + + info.daily_cap = campaign.daily_cap; + info.advertiser_id = campaign.advertiser_id; + info.priority = campaign.priority; + info.ptr = campaign.ptr; + info.conversion = creative_set.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.description = creative.payload.description; + info.target_url = creative.payload.target_url; + + // Segments + for (const auto& segment : creative_set.segments) { + auto segment_name = base::ToLowerASCII(segment.name); + + 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.creative_set_id + << " segment name should not be empty"); + + continue; + } + + info.segment = segment_name; + creative_promoted_content_ads.push_back(info); + entries++; + + auto top_level_segment_name = segment_name_hierarchy.front(); + if (top_level_segment_name != segment_name) { + info.segment = top_level_segment_name; + creative_promoted_content_ads.push_back(info); + entries++; + } + } + } + if (entries == 0) { BLOG(1, "creative set id " << creative_set.creative_set_id << " has no entries"); @@ -289,6 +375,7 @@ BundleState Bundle::FromCatalog( BundleState bundle_state; bundle_state.creative_ad_notifications = creative_ad_notifications; bundle_state.creative_new_tab_page_ads = creative_new_tab_page_ads; + bundle_state.creative_promoted_content_ads = creative_promoted_content_ads; bundle_state.conversions = conversions; return bundle_state; @@ -297,6 +384,7 @@ BundleState Bundle::FromCatalog( void Bundle::DeleteDatabaseTables() { DeleteCreativeAdNotifications(); DeleteCreativeNewTabPageAds(); + DeleteCreativePromotedContentAds(); DeleteCampaigns(); DeleteSegments(); DeleteCreativeAds(); @@ -330,6 +418,19 @@ void Bundle::DeleteCreativeNewTabPageAds() { }); } +void Bundle::DeleteCreativePromotedContentAds() { + database::table::CreativePromotedContentAds database_table; + database_table.Delete([]( + const Result result) { + if (result != SUCCESS) { + BLOG(0, "Failed to delete creative promoted content ads state"); + return; + } + + BLOG(3, "Successfully deleted creative promoted content ads state"); + }); +} + void Bundle::DeleteCampaigns() { database::table::Campaigns database_table; database_table.Delete([]( @@ -425,6 +526,21 @@ void Bundle::SaveCreativeNewTabPageAds( }); } +void Bundle::SaveCreativePromotedContentAds( + const CreativePromotedContentAdList& creative_promoted_content_ads) { + database::table::CreativePromotedContentAds database_table; + + database_table.Save(creative_promoted_content_ads, []( + const Result result) { + if (result != SUCCESS) { + BLOG(0, "Failed to save creative promoted content ads state"); + return; + } + + BLOG(3, "Successfully saved creative promoted content ads state"); + }); +} + void Bundle::PurgeExpiredConversions() { database::table::Conversions database_table; database_table.PurgeExpired([]( 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 8ad18a7a7415..74c6281a1399 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 @@ -8,6 +8,7 @@ #include "bat/ads/internal/bundle/creative_ad_notification_info.h" #include "bat/ads/internal/bundle/creative_new_tab_page_ad_info.h" +#include "bat/ads/internal/bundle/creative_promoted_content_ad_info.h" #include "bat/ads/internal/conversions/conversion_info.h" namespace ads { @@ -30,20 +31,24 @@ class Bundle { void DeleteDatabaseTables(); - void DeleteCreativeAdNotifications(); - void DeleteCreativeNewTabPageAds(); void DeleteCampaigns(); void DeleteSegments(); void DeleteCreativeAds(); void DeleteDayparts(); void DeleteGeoTargets(); + void DeleteCreativeAdNotifications(); void SaveCreativeAdNotifications( const CreativeAdNotificationList& creative_ad_notifications); + void DeleteCreativeNewTabPageAds(); void SaveCreativeNewTabPageAds( const CreativeNewTabPageAdList& creative_new_tab_page_ads); + void DeleteCreativePromotedContentAds(); + void SaveCreativePromotedContentAds( + const CreativePromotedContentAdList& creative_promoted_content_ads); + void PurgeExpiredConversions(); void SaveConversions( const ConversionList& conversions); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle_state.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle_state.h index ee901f007cc9..6448f34d73fb 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle_state.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/bundle_state.h @@ -8,6 +8,7 @@ #include "bat/ads/internal/bundle/creative_ad_notification_info.h" #include "bat/ads/internal/bundle/creative_new_tab_page_ad_info.h" +#include "bat/ads/internal/bundle/creative_promoted_content_ad_info.h" #include "bat/ads/internal/conversions/conversion_info.h" namespace ads { @@ -20,6 +21,7 @@ struct BundleState { CreativeAdNotificationList creative_ad_notifications; CreativeNewTabPageAdList creative_new_tab_page_ads; + CreativePromotedContentAdList creative_promoted_content_ads; ConversionList conversions; }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_promoted_content_ad_info.cc b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_promoted_content_ad_info.cc new file mode 100644 index 000000000000..ca54e2762b1c --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_promoted_content_ad_info.cc @@ -0,0 +1,25 @@ +/* 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/bundle/creative_promoted_content_ad_info.h" + +namespace ads { + +CreativePromotedContentAdInfo::CreativePromotedContentAdInfo() = default; + +CreativePromotedContentAdInfo::~CreativePromotedContentAdInfo() = default; + +bool CreativePromotedContentAdInfo::operator==( + const CreativePromotedContentAdInfo& rhs) const { + return title == rhs.title && + description == rhs.description; +} + +bool CreativePromotedContentAdInfo::operator!=( + const CreativePromotedContentAdInfo& rhs) const { + return !(*this == rhs); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_promoted_content_ad_info.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_promoted_content_ad_info.h new file mode 100644 index 000000000000..928bce4e498d --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_promoted_content_ad_info.h @@ -0,0 +1,35 @@ +/* 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_BUNDLE_CREATIVE_PROMOTED_CONTENT_AD_INFO_H_ +#define BAT_ADS_INTERNAL_BUNDLE_CREATIVE_PROMOTED_CONTENT_AD_INFO_H_ + +#include +#include + +#include "bat/ads/internal/bundle/creative_ad_info.h" + +namespace ads { + +struct CreativePromotedContentAdInfo : CreativeAdInfo { + CreativePromotedContentAdInfo(); + ~CreativePromotedContentAdInfo(); + + bool operator==( + const CreativePromotedContentAdInfo& rhs) const; + + bool operator!=( + const CreativePromotedContentAdInfo& rhs) const; + + std::string title; + std::string description; +}; + +using CreativePromotedContentAdList = + std::vector; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_BUNDLE_CREATIVE_PROMOTED_CONTENT_AD_INFO_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_promoted_content_ad_info.cc b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_promoted_content_ad_info.cc new file mode 100644 index 000000000000..c059282d765c --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_promoted_content_ad_info.cc @@ -0,0 +1,29 @@ +/* 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/catalog/catalog_creative_promoted_content_ad_info.h" + +namespace ads { + +CatalogCreativePromotedContentAdInfo:: +CatalogCreativePromotedContentAdInfo() = default; + +CatalogCreativePromotedContentAdInfo::CatalogCreativePromotedContentAdInfo( + const CatalogCreativePromotedContentAdInfo& info) = default; + +CatalogCreativePromotedContentAdInfo:: +~CatalogCreativePromotedContentAdInfo() = default; + +bool CatalogCreativePromotedContentAdInfo::operator==( + const CatalogCreativePromotedContentAdInfo& rhs) const { + return payload == rhs.payload; +} + +bool CatalogCreativePromotedContentAdInfo::operator!=( + const CatalogCreativePromotedContentAdInfo& rhs) const { + return !(*this == rhs); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_promoted_content_ad_info.h b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_promoted_content_ad_info.h new file mode 100644 index 000000000000..f5878585c88e --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_promoted_content_ad_info.h @@ -0,0 +1,35 @@ +/* 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_CATALOG_CATALOG_CREATIVE_PROMOTED_CONTENT_AD_INFO_H_ +#define BAT_ADS_INTERNAL_CATALOG_CATALOG_CREATIVE_PROMOTED_CONTENT_AD_INFO_H_ + +#include + +#include "bat/ads/internal/catalog/catalog_creative_info.h" +#include "bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.h" + +namespace ads { + +struct CatalogCreativePromotedContentAdInfo : CatalogCreativeInfo { + CatalogCreativePromotedContentAdInfo(); + CatalogCreativePromotedContentAdInfo( + const CatalogCreativePromotedContentAdInfo& info); + ~CatalogCreativePromotedContentAdInfo(); + + bool operator==( + const CatalogCreativePromotedContentAdInfo& rhs) const; + bool operator!=( + const CatalogCreativePromotedContentAdInfo& rhs) const; + + CatalogPromotedContentAdPayloadInfo payload; +}; + +using CatalogCreativePromotedContentAdList = + std::vector; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_CATALOG_CATALOG_CREATIVE_PROMOTED_CONTENT_AD_INFO_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_set_info.h b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_set_info.h index f46a950572ef..e333971eec9a 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_set_info.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_creative_set_info.h @@ -11,6 +11,7 @@ #include "bat/ads/internal/catalog/catalog_creative_ad_notification_info.h" #include "bat/ads/internal/catalog/catalog_creative_new_tab_page_ad_info.h" +#include "bat/ads/internal/catalog/catalog_creative_promoted_content_ad_info.h" #include "bat/ads/internal/catalog/catalog_os_info.h" #include "bat/ads/internal/catalog/catalog_segment_info.h" #include "bat/ads/internal/conversions/conversion_info.h" @@ -35,6 +36,7 @@ struct CatalogCreativeSetInfo { CatalogOsList oses; CatalogCreativeAdNotificationList creative_ad_notifications; CatalogCreativeNewTabPageAdList creative_new_tab_page_ads; + CatalogCreativePromotedContentAdList creative_promoted_content_ads; ConversionList conversions; }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.cc b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.cc new file mode 100644 index 000000000000..e2dc684ea0f6 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.cc @@ -0,0 +1,31 @@ +/* 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/catalog/catalog_promoted_content_ad_payload_info.h" + +namespace ads { + +CatalogPromotedContentAdPayloadInfo:: +CatalogPromotedContentAdPayloadInfo() = default; + +CatalogPromotedContentAdPayloadInfo::CatalogPromotedContentAdPayloadInfo( + const CatalogPromotedContentAdPayloadInfo& info) = default; + +CatalogPromotedContentAdPayloadInfo:: +~CatalogPromotedContentAdPayloadInfo() = default; + +bool CatalogPromotedContentAdPayloadInfo::operator==( + const CatalogPromotedContentAdPayloadInfo& rhs) const { + return title == rhs.title && + description == rhs.description && + target_url == rhs.target_url; +} + +bool CatalogPromotedContentAdPayloadInfo::operator!=( + const CatalogPromotedContentAdPayloadInfo& rhs) const { + return !(*this == rhs); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.h b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.h new file mode 100644 index 000000000000..2d1ba4dfd807 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_promoted_content_ad_payload_info.h @@ -0,0 +1,31 @@ +/* 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_CATALOG_CATALOG_PROMOTED_CONTENT_AD_PAYLOAD_INFO_H_ +#define BAT_ADS_INTERNAL_CATALOG_CATALOG_PROMOTED_CONTENT_AD_PAYLOAD_INFO_H_ + +#include + +namespace ads { + +struct CatalogPromotedContentAdPayloadInfo { + CatalogPromotedContentAdPayloadInfo(); + CatalogPromotedContentAdPayloadInfo( + const CatalogPromotedContentAdPayloadInfo& info); + ~CatalogPromotedContentAdPayloadInfo(); + + bool operator==( + const CatalogPromotedContentAdPayloadInfo& rhs) const; + bool operator!=( + const CatalogPromotedContentAdPayloadInfo& rhs) const; + + std::string title; + std::string description; + std::string target_url; +}; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_CATALOG_CATALOG_PROMOTED_CONTENT_AD_PAYLOAD_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 718ec045b107..18e25934fa2d 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 @@ -44,7 +44,7 @@ Result CatalogState::FromJson( new_catalog_id = document["catalogId"].GetString(); new_version = document["version"].GetInt(); - if (new_version != 5) { + if (new_version != 6) { return FAILED; } @@ -209,6 +209,31 @@ Result CatalogState::FromJson( } creative_set_info.creative_new_tab_page_ads.push_back(creative_info); + } else if (code == "promoted_content_all_v1") { + CatalogCreativePromotedContentAdInfo creative_info; + + creative_info.creative_instance_id = creative_instance_id; + + // Type + creative_info.type.code = code; + creative_info.type.name = type["name"].GetString(); + creative_info.type.platform = type["platform"].GetString(); + creative_info.type.version = type["version"].GetUint64(); + + // Payload + auto payload = creative["payload"].GetObject(); + creative_info.payload.title = payload["title"].GetString(); + creative_info.payload.description = + payload["description"].GetString(); + creative_info.payload.target_url = payload["feed"].GetString(); + if (!GURL(creative_info.payload.target_url).is_valid()) { + BLOG(1, "Invalid target URL for creative instance id " + << creative_instance_id); + continue; + } + + creative_set_info.creative_promoted_content_ads.push_back( + creative_info); } else if (code == "in_page_all_v1") { // TODO(tmancey): https://github.com/brave/brave-browser/issues/7298 continue; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc index a6d64eb0ad2c..0c359e952170 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc @@ -90,7 +90,7 @@ class BatAdsCatalogTest : public UnitTestBase { 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 = "Brave 1"; + catalog_creative_new_tab_page_ad.payload.company_name = "New Tab Page 1"; catalog_creative_new_tab_page_ad.payload.alt = "Test New Tab Page Ad Campaign 1"; catalog_creative_new_tab_page_ad.payload.target_url = @@ -98,6 +98,27 @@ class BatAdsCatalogTest : public UnitTestBase { catalog_creative_new_tab_page_ads.push_back( catalog_creative_new_tab_page_ad); + // Creative Promoted Content Ads + CatalogCreativePromotedContentAdList catalog_creative_promoted_content_ads; + + CatalogCreativePromotedContentAdInfo catalog_creative_promoted_content_ad; + catalog_creative_promoted_content_ad.creative_instance_id = + "60001aa5-9368-45d2-81fc-e69887d278c5"; + CatalogTypeInfo catalog_type_promoted_content_ad_type; + catalog_type_promoted_content_ad_type.code = "promoted_content_all_v1"; + catalog_type_promoted_content_ad_type.name = "promoted_content"; + catalog_type_promoted_content_ad_type.platform = "all"; + catalog_type_promoted_content_ad_type.version = 1; + catalog_creative_promoted_content_ad.type = + catalog_type_promoted_content_ad_type; + catalog_creative_promoted_content_ad.payload.title = "Promoted Content 1"; + catalog_creative_promoted_content_ad.payload.description = + "Test Promoted Content Ad Campaign 1"; + catalog_creative_promoted_content_ad.payload.target_url = + "https://brave.com/1/promoted_content_ad"; + catalog_creative_promoted_content_ads.push_back( + catalog_creative_promoted_content_ad); + // Conversions ConversionList conversions; @@ -123,6 +144,8 @@ class BatAdsCatalogTest : public UnitTestBase { catalog_creative_ad_notifications; 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 = conversions; catalog_creative_sets.push_back(catalog_creative_set); @@ -221,7 +244,7 @@ class BatAdsCatalogTest : public UnitTestBase { 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 = "Brave 2"; + catalog_creative_new_tab_page_ad.payload.company_name = "New Tab Page 2"; catalog_creative_new_tab_page_ad.payload.alt = "Test New Tab Page Ad Campaign 2"; catalog_creative_new_tab_page_ad.payload.target_url = @@ -229,6 +252,27 @@ class BatAdsCatalogTest : public UnitTestBase { catalog_creative_new_tab_page_ads.push_back( catalog_creative_new_tab_page_ad); + // Creative Promoted Content Ads + CatalogCreativePromotedContentAdList catalog_creative_promoted_content_ads; + + CatalogCreativePromotedContentAdInfo catalog_creative_promoted_content_ad; + catalog_creative_promoted_content_ad.creative_instance_id = + "9f2f49ab-77d7-4e99-9428-472dc8e04f90"; + CatalogTypeInfo catalog_type_promoted_content_ad_type; + catalog_type_promoted_content_ad_type.code = "promoted_content_all_v1"; + catalog_type_promoted_content_ad_type.name = "promoted_content"; + catalog_type_promoted_content_ad_type.platform = "all"; + catalog_type_promoted_content_ad_type.version = 1; + catalog_creative_promoted_content_ad.type = + catalog_type_promoted_content_ad_type; + catalog_creative_promoted_content_ad.payload.title = "Promoted Content 2"; + catalog_creative_promoted_content_ad.payload.description = + "Test Promoted Content Ad Campaign 2"; + catalog_creative_promoted_content_ad.payload.target_url = + "https://brave.com/2/promoted_content_ad"; + catalog_creative_promoted_content_ads.push_back( + catalog_creative_promoted_content_ad); + // Conversions ConversionList conversions; @@ -254,6 +298,8 @@ class BatAdsCatalogTest : public UnitTestBase { catalog_creative_ad_notifications; 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 = conversions; catalog_creative_sets.push_back(catalog_creative_set); @@ -412,7 +458,7 @@ TEST_F(BatAdsCatalogTest, const int version = catalog.GetVersion(); // Assert - EXPECT_EQ(5, version); + EXPECT_EQ(6, version); } TEST_F(BatAdsCatalogTest, 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 229d152533ad..78e119486e15 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/creative_promoted_content_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/database/tables/segments_database_table.h" @@ -80,6 +81,10 @@ void Migration::ToVersion( table::CreativeNewTabPageAds creative_new_tab_page_ads_database_table; creative_new_tab_page_ads_database_table.Migrate(transaction, to_version); + table::CreativePromotedContentAds + creative_promoted_content_ads_database_table; + creative_promoted_content_ads_database_table.Migrate(transaction, to_version); + table::CreativeAds creative_ads_database_table; creative_ads_database_table.Migrate(transaction, to_version); 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 6da4b685d6a2..d26a7d24476b 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 8; + return 9; } int32_t compatible_version() { - return 8; + return 9; } } // namespace database diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/campaigns_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/campaigns_database_table.cc index 85c3f071022b..e38d649a5f3b 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/campaigns_database_table.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/campaigns_database_table.cc @@ -63,8 +63,8 @@ void Campaigns::Migrate( DCHECK(transaction); switch (to_version) { - case 8: { - MigrateToV8(transaction); + case 9: { + MigrateToV9(transaction); break; } @@ -117,7 +117,7 @@ std::string Campaigns::BuildInsertOrUpdateQuery( BuildBindingParameterPlaceholders(7, count).c_str()); } -void Campaigns::CreateTableV8( +void Campaigns::CreateTableV9( DBTransaction* transaction) { DCHECK(transaction); @@ -139,13 +139,13 @@ void Campaigns::CreateTableV8( transaction->commands.push_back(std::move(command)); } -void Campaigns::MigrateToV8( +void Campaigns::MigrateToV9( DBTransaction* transaction) { DCHECK(transaction); util::Drop(transaction, get_table_name()); - CreateTableV8(transaction); + CreateTableV9(transaction); } } // namespace table diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/campaigns_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/campaigns_database_table.h index 74080b54f25f..30cdf84b8c3a 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/campaigns_database_table.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/campaigns_database_table.h @@ -45,9 +45,9 @@ class Campaigns : public Table { DBCommand* command, const CreativeAdList& creative_ads); - void CreateTableV8( + void CreateTableV9( DBTransaction* transaction); - void MigrateToV8( + void MigrateToV9( DBTransaction* transaction); }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/conversions_database_table_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/conversions_database_table_test.cc index ea2a24772c16..67bd743006d2 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/conversions_database_table_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/conversions_database_table_test.cc @@ -29,7 +29,7 @@ TEST_F(BatAdsConversionsDatabaseTableIntegrationTest, // Arrange const URLEndpoints endpoints = { { - "/v5/catalog", { + "/v6/catalog", { { net::HTTP_OK, "/catalog.json" } 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 c02bd7f01b7d..bccceaf5e35a 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 @@ -261,8 +261,8 @@ void CreativeAdNotifications::Migrate( DCHECK(transaction); switch (to_version) { - case 8: { - MigrateToV8(transaction); + case 9: { + MigrateToV9(transaction); break; } @@ -410,7 +410,7 @@ CreativeAdNotificationInfo CreativeAdNotifications::GetFromRecord( return creative_ad_notification; } -void CreativeAdNotifications::CreateTableV8( +void CreativeAdNotifications::CreateTableV9( DBTransaction* transaction) { DCHECK(transaction); @@ -431,13 +431,13 @@ void CreativeAdNotifications::CreateTableV8( transaction->commands.push_back(std::move(command)); } -void CreativeAdNotifications::MigrateToV8( +void CreativeAdNotifications::MigrateToV9( DBTransaction* transaction) { DCHECK(transaction); util::Drop(transaction, get_table_name()); - CreateTableV8(transaction); + CreateTableV9(transaction); } } // namespace table 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 9f2f6de5cdff..88863181b6e1 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 @@ -84,9 +84,9 @@ class CreativeAdNotifications : public Table { CreativeAdNotificationInfo GetFromRecord( DBRecord* record) const; - void CreateTableV8( + void CreateTableV9( DBTransaction* transaction); - void MigrateToV8( + void MigrateToV9( DBTransaction* transaction); int batch_size_; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_test.cc index b3ab484bfe88..6846d6d7ad19 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_test.cc @@ -31,7 +31,7 @@ TEST_F(BatAdsCreativeAdNotificationsDatabaseTableIntegrationTest, // Arrange const URLEndpoints endpoints = { { - "/v5/catalog", { + "/v6/catalog", { { net::HTTP_OK, "/catalog.json" } diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ads_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ads_database_table.cc index f12d110cba29..f94c17fb1700 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ads_database_table.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ads_database_table.cc @@ -62,8 +62,8 @@ void CreativeAds::Migrate( DCHECK(transaction); switch (to_version) { - case 8: { - MigrateToV8(transaction); + case 9: { + MigrateToV9(transaction); break; } @@ -112,7 +112,7 @@ std::string CreativeAds::BuildInsertOrUpdateQuery( BuildBindingParameterPlaceholders(5, count).c_str()); } -void CreativeAds::CreateTableV8( +void CreativeAds::CreateTableV9( DBTransaction* transaction) { DCHECK(transaction); @@ -133,13 +133,13 @@ void CreativeAds::CreateTableV8( transaction->commands.push_back(std::move(command)); } -void CreativeAds::MigrateToV8( +void CreativeAds::MigrateToV9( DBTransaction* transaction) { DCHECK(transaction); util::Drop(transaction, get_table_name()); - CreateTableV8(transaction); + CreateTableV9(transaction); } } // namespace table diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ads_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ads_database_table.h index 64d9001165f1..22dffe43d754 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ads_database_table.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ads_database_table.h @@ -45,9 +45,9 @@ class CreativeAds : public Table { DBCommand* command, const CreativeAdList& creative_ads); - void CreateTableV8( + void CreateTableV9( DBTransaction* transaction); - void MigrateToV8( + void MigrateToV9( DBTransaction* transaction); }; 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 674b2eb2c7e6..52f799fdeb5f 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 @@ -94,9 +94,9 @@ void CreativeNewTabPageAds::GetForCreativeInstanceId( const std::string query = base::StringPrintf( "SELECT " - "can.creative_instance_id, " - "can.creative_set_id, " - "can.campaign_id, " + "cntpa.creative_instance_id, " + "cntpa.creative_set_id, " + "cntpa.campaign_id, " "cam.start_at_timestamp, " "cam.end_at_timestamp, " "cam.daily_cap, " @@ -108,24 +108,24 @@ void CreativeNewTabPageAds::GetForCreativeInstanceId( "s.segment, " "gt.geo_target, " "ca.target_url, " - "can.company_name, " - "can.alt, " + "cntpa.company_name, " + "cntpa.alt, " "cam.ptr, " "dp.dow, " "dp.start_minute, " "dp.end_minute " - "FROM %s AS can " + "FROM %s AS cntpa " "INNER JOIN campaigns AS cam " - "ON cam.campaign_id = can.campaign_id " + "ON cam.campaign_id = cntpa.campaign_id " "INNER JOIN segments AS s " - "ON s.creative_set_id = can.creative_set_id " + "ON s.creative_set_id = cntpa.creative_set_id " "INNER JOIN creative_ads AS ca " - "ON ca.creative_instance_id = can.creative_instance_id " + "ON ca.creative_instance_id = cntpa.creative_instance_id " "INNER JOIN geo_targets AS gt " - "ON gt.campaign_id = can.campaign_id " + "ON gt.campaign_id = cntpa.campaign_id " "INNER JOIN dayparts AS dp " - "ON dp.campaign_id = can.campaign_id " - "WHERE can.creative_instance_id = '%s'", + "ON dp.campaign_id = cntpa.campaign_id " + "WHERE cntpa.creative_instance_id = '%s'", get_table_name().c_str(), creative_instance_id.c_str()); @@ -174,9 +174,9 @@ void CreativeNewTabPageAds::GetForSegments( const std::string query = base::StringPrintf( "SELECT " - "can.creative_instance_id, " - "can.creative_set_id, " - "can.campaign_id, " + "cntpa.creative_instance_id, " + "cntpa.creative_set_id, " + "cntpa.campaign_id, " "cam.start_at_timestamp, " "cam.end_at_timestamp, " "cam.daily_cap, " @@ -188,23 +188,23 @@ void CreativeNewTabPageAds::GetForSegments( "s.segment, " "gt.geo_target, " "ca.target_url, " - "can.company_name, " - "can.alt, " + "cntpa.company_name, " + "cntpa.alt, " "cam.ptr, " "dp.dow, " "dp.start_minute, " "dp.end_minute " - "FROM %s AS can " + "FROM %s AS cntpa " "INNER JOIN campaigns AS cam " - "ON cam.campaign_id = can.campaign_id " + "ON cam.campaign_id = cntpa.campaign_id " "INNER JOIN segments AS s " - "ON s.creative_set_id = can.creative_set_id " + "ON s.creative_set_id = cntpa.creative_set_id " "INNER JOIN creative_ads AS ca " - "ON ca.creative_instance_id = can.creative_instance_id " + "ON ca.creative_instance_id = cntpa.creative_instance_id " "INNER JOIN geo_targets AS gt " - "ON gt.campaign_id = can.campaign_id " + "ON gt.campaign_id = cntpa.campaign_id " "INNER JOIN dayparts AS dp " - "ON dp.campaign_id = can.campaign_id " + "ON dp.campaign_id = cntpa.campaign_id " "WHERE s.segment IN %s " "AND %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", get_table_name().c_str(), @@ -256,9 +256,9 @@ void CreativeNewTabPageAds::GetAll( GetCreativeNewTabPageAdsCallback callback) { const std::string query = base::StringPrintf( "SELECT " - "can.creative_instance_id, " - "can.creative_set_id, " - "can.campaign_id, " + "cntpa.creative_instance_id, " + "cntpa.creative_set_id, " + "cntpa.campaign_id, " "cam.start_at_timestamp, " "cam.end_at_timestamp, " "cam.daily_cap, " @@ -270,23 +270,23 @@ void CreativeNewTabPageAds::GetAll( "s.segment, " "gt.geo_target, " "ca.target_url, " - "can.company_name, " - "can.alt, " + "cntpa.company_name, " + "cntpa.alt, " "cam.ptr, " "dp.dow, " "dp.start_minute, " "dp.end_minute " - "FROM %s AS can " + "FROM %s AS cntpa " "INNER JOIN campaigns AS cam " - "ON cam.campaign_id = can.campaign_id " + "ON cam.campaign_id = cntpa.campaign_id " "INNER JOIN segments AS s " - "ON s.creative_set_id = can.creative_set_id " + "ON s.creative_set_id = cntpa.creative_set_id " "INNER JOIN creative_ads AS ca " - "ON ca.creative_instance_id = can.creative_instance_id " + "ON ca.creative_instance_id = cntpa.creative_instance_id " "INNER JOIN geo_targets AS gt " - "ON gt.campaign_id = can.campaign_id " + "ON gt.campaign_id = cntpa.campaign_id " "INNER JOIN dayparts AS dp " - "ON dp.campaign_id = can.campaign_id " + "ON dp.campaign_id = cntpa.campaign_id " "WHERE %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", get_table_name().c_str(), TimeAsTimestampString(base::Time::Now()).c_str()); @@ -343,8 +343,8 @@ void CreativeNewTabPageAds::Migrate( DCHECK(transaction); switch (to_version) { - case 8: { - MigrateToV8(transaction); + case 9: { + MigrateToV9(transaction); break; } @@ -516,7 +516,7 @@ CreativeNewTabPageAdInfo CreativeNewTabPageAds::GetFromRecord( return creative_new_tab_page_ad; } -void CreativeNewTabPageAds::CreateTableV8( +void CreativeNewTabPageAds::CreateTableV9( DBTransaction* transaction) { DCHECK(transaction); @@ -537,13 +537,13 @@ void CreativeNewTabPageAds::CreateTableV8( transaction->commands.push_back(std::move(command)); } -void CreativeNewTabPageAds::MigrateToV8( +void CreativeNewTabPageAds::MigrateToV9( DBTransaction* transaction) { DCHECK(transaction); util::Drop(transaction, get_table_name()); - CreateTableV8(transaction); + CreateTableV9(transaction); } } // namespace table 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 a6d865127cb7..7a26b02d8201 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 @@ -96,9 +96,9 @@ class CreativeNewTabPageAds : public Table { CreativeNewTabPageAdInfo GetFromRecord( DBRecord* record) const; - void CreateTableV8( + void CreateTableV9( DBTransaction* transaction); - void MigrateToV8( + void MigrateToV9( DBTransaction* transaction); int batch_size_; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_test.cc index a8e61b70aafa..51f4667582a5 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_test.cc @@ -30,7 +30,7 @@ TEST_F(BatAdsCreativeNewTabPageAdsDatabaseTableIntegrationTest, // Arrange const URLEndpoints endpoints = { { - "/v5/catalog", { + "/v6/catalog", { { net::HTTP_OK, "/catalog.json" } diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table.cc new file mode 100644 index 000000000000..82e9cf09d222 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table.cc @@ -0,0 +1,554 @@ +/* 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/creative_promoted_content_ads_database_table.h" + +#include +#include + +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "bat/ads/internal/ads_client_helper.h" +#include "bat/ads/internal/container_util.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/logging.h" +#include "bat/ads/internal/time_formatting_util.h" + +namespace ads { +namespace database { +namespace table { + +namespace { + +const char kTableName[] = "creative_promoted_content_ads"; + +const int kDefaultBatchSize = 50; + +} // namespace + +CreativePromotedContentAds::CreativePromotedContentAds() + : batch_size_(kDefaultBatchSize), + campaigns_database_table_(std::make_unique()), + creative_ads_database_table_(std::make_unique()), + dayparts_database_table_(std::make_unique()), + geo_targets_database_table_(std::make_unique()), + segments_database_table_(std::make_unique()) { +} + +CreativePromotedContentAds::~CreativePromotedContentAds() = default; + +void CreativePromotedContentAds::Save( + const CreativePromotedContentAdList& creative_promoted_content_ads, + ResultCallback callback) { + if (creative_promoted_content_ads.empty()) { + callback(Result::SUCCESS); + return; + } + + DBTransactionPtr transaction = DBTransaction::New(); + + const std::vector batches = + SplitVector(creative_promoted_content_ads, batch_size_); + + for (const auto& batch : batches) { + InsertOrUpdate(transaction.get(), batch); + + std::vector creative_ads(batch.begin(), batch.end()); + campaigns_database_table_->InsertOrUpdate(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); + segments_database_table_->InsertOrUpdate(transaction.get(), creative_ads); + } + + AdsClientHelper::Get()->RunDBTransaction(std::move(transaction), + std::bind(&OnResultCallback, std::placeholders::_1, callback)); +} + +void CreativePromotedContentAds::Delete( + ResultCallback callback) { + DBTransactionPtr transaction = DBTransaction::New(); + + util::Delete(transaction.get(), get_table_name()); + + AdsClientHelper::Get()->RunDBTransaction(std::move(transaction), + std::bind(&OnResultCallback, std::placeholders::_1, callback)); +} + +void CreativePromotedContentAds::GetForCreativeInstanceId( + const std::string& creative_instance_id, + GetCreativePromotedContentAdCallback callback) { + CreativePromotedContentAdInfo creative_promoted_content_ad; + + if (creative_instance_id.empty()) { + callback(Result::FAILED, creative_instance_id, + creative_promoted_content_ad); + return; + } + + const std::string query = base::StringPrintf( + "SELECT " + "cpca.creative_instance_id, " + "cpca.creative_set_id, " + "cpca.campaign_id, " + "cam.start_at_timestamp, " + "cam.end_at_timestamp, " + "cam.daily_cap, " + "cam.advertiser_id, " + "cam.priority, " + "ca.conversion, " + "ca.per_day, " + "ca.total_max, " + "s.segment, " + "gt.geo_target, " + "ca.target_url, " + "cpca.title, " + "cpca.description, " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " + "FROM %s AS cpca " + "INNER JOIN campaigns AS cam " + "ON cam.campaign_id = cpca.campaign_id " + "INNER JOIN segments AS s " + "ON s.creative_set_id = cpca.creative_set_id " + "INNER JOIN creative_ads AS ca " + "ON ca.creative_instance_id = cpca.creative_instance_id " + "INNER JOIN geo_targets AS gt " + "ON gt.campaign_id = cpca.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = cpca.campaign_id " + "WHERE cpca.creative_instance_id = '%s'", + get_table_name().c_str(), + creative_instance_id.c_str()); + + DBCommandPtr command = DBCommand::New(); + command->type = DBCommand::Type::READ; + command->command = query; + + command->record_bindings = { + DBCommand::RecordBindingType::STRING_TYPE, // creative_instance_id + DBCommand::RecordBindingType::STRING_TYPE, // creative_set_id + DBCommand::RecordBindingType::STRING_TYPE, // campaign_id + DBCommand::RecordBindingType::INT64_TYPE, // start_at_timestamp + DBCommand::RecordBindingType::INT64_TYPE, // end_at_timestamp + DBCommand::RecordBindingType::INT_TYPE, // daily_cap + DBCommand::RecordBindingType::STRING_TYPE, // advertiser_id + DBCommand::RecordBindingType::INT_TYPE, // priority + DBCommand::RecordBindingType::BOOL_TYPE, // conversion + DBCommand::RecordBindingType::INT_TYPE, // per_day + DBCommand::RecordBindingType::INT_TYPE, // total_max + DBCommand::RecordBindingType::STRING_TYPE, // segment + DBCommand::RecordBindingType::STRING_TYPE, // geo_target + DBCommand::RecordBindingType::STRING_TYPE, // target_url + DBCommand::RecordBindingType::STRING_TYPE, // title + DBCommand::RecordBindingType::STRING_TYPE, // description + 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(); + transaction->commands.push_back(std::move(command)); + + AdsClientHelper::Get()->RunDBTransaction(std::move(transaction), + std::bind(&CreativePromotedContentAds::OnGetForCreativeInstanceId, this, + std::placeholders::_1, creative_instance_id, callback)); +} + +void CreativePromotedContentAds::GetForSegments( + const SegmentList& segments, + GetCreativePromotedContentAdsCallback callback) { + if (segments.empty()) { + callback(Result::SUCCESS, segments, {}); + return; + } + + const std::string query = base::StringPrintf( + "SELECT " + "cpca.creative_instance_id, " + "cpca.creative_set_id, " + "cpca.campaign_id, " + "cam.start_at_timestamp, " + "cam.end_at_timestamp, " + "cam.daily_cap, " + "cam.advertiser_id, " + "cam.priority, " + "ca.conversion, " + "ca.per_day, " + "ca.total_max, " + "s.segment, " + "gt.geo_target, " + "ca.target_url, " + "cpca.title, " + "cpca.description, " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " + "FROM %s AS cpca " + "INNER JOIN campaigns AS cam " + "ON cam.campaign_id = cpca.campaign_id " + "INNER JOIN segments AS s " + "ON s.creative_set_id = cpca.creative_set_id " + "INNER JOIN creative_ads AS ca " + "ON ca.creative_instance_id = cpca.creative_instance_id " + "INNER JOIN geo_targets AS gt " + "ON gt.campaign_id = cpca.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = cpca.campaign_id " + "WHERE s.segment IN %s " + "AND %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", + get_table_name().c_str(), + BuildBindingParameterPlaceholder(segments.size()).c_str(), + TimeAsTimestampString(base::Time::Now()).c_str()); + + DBCommandPtr command = DBCommand::New(); + command->type = DBCommand::Type::READ; + command->command = query; + + int index = 0; + for (const auto& segment : segments) { + BindString(command.get(), index, base::ToLowerASCII(segment)); + index++; + } + + command->record_bindings = { + DBCommand::RecordBindingType::STRING_TYPE, // creative_instance_id + DBCommand::RecordBindingType::STRING_TYPE, // creative_set_id + DBCommand::RecordBindingType::STRING_TYPE, // campaign_id + DBCommand::RecordBindingType::INT64_TYPE, // start_at_timestamp + DBCommand::RecordBindingType::INT64_TYPE, // end_at_timestamp + DBCommand::RecordBindingType::INT_TYPE, // daily_cap + DBCommand::RecordBindingType::STRING_TYPE, // advertiser_id + DBCommand::RecordBindingType::INT_TYPE, // priority + DBCommand::RecordBindingType::BOOL_TYPE, // conversion + DBCommand::RecordBindingType::INT_TYPE, // per_day + DBCommand::RecordBindingType::INT_TYPE, // total_max + DBCommand::RecordBindingType::STRING_TYPE, // segment + DBCommand::RecordBindingType::STRING_TYPE, // geo_target + DBCommand::RecordBindingType::STRING_TYPE, // target_url + DBCommand::RecordBindingType::STRING_TYPE, // title + DBCommand::RecordBindingType::STRING_TYPE, // description + 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(); + transaction->commands.push_back(std::move(command)); + + AdsClientHelper::Get()->RunDBTransaction(std::move(transaction), + std::bind(&CreativePromotedContentAds::OnGetForSegments, this, + std::placeholders::_1, segments, callback)); +} + +void CreativePromotedContentAds::GetAll( + GetCreativePromotedContentAdsCallback callback) { + const std::string query = base::StringPrintf( + "SELECT " + "cpca.creative_instance_id, " + "cpca.creative_set_id, " + "cpca.campaign_id, " + "cam.start_at_timestamp, " + "cam.end_at_timestamp, " + "cam.daily_cap, " + "cam.advertiser_id, " + "cam.priority, " + "ca.conversion, " + "ca.per_day, " + "ca.total_max, " + "s.segment, " + "gt.geo_target, " + "ca.target_url, " + "cpca.title, " + "cpca.description, " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " + "FROM %s AS cpca " + "INNER JOIN campaigns AS cam " + "ON cam.campaign_id = cpca.campaign_id " + "INNER JOIN segments AS s " + "ON s.creative_set_id = cpca.creative_set_id " + "INNER JOIN creative_ads AS ca " + "ON ca.creative_instance_id = cpca.creative_instance_id " + "INNER JOIN geo_targets AS gt " + "ON gt.campaign_id = cpca.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = cpca.campaign_id " + "WHERE %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", + get_table_name().c_str(), + TimeAsTimestampString(base::Time::Now()).c_str()); + + DBCommandPtr command = DBCommand::New(); + command->type = DBCommand::Type::READ; + command->command = query; + + command->record_bindings = { + DBCommand::RecordBindingType::STRING_TYPE, // creative_instance_id + DBCommand::RecordBindingType::STRING_TYPE, // creative_set_id + DBCommand::RecordBindingType::STRING_TYPE, // campaign_id + DBCommand::RecordBindingType::INT64_TYPE, // start_at_timestamp + DBCommand::RecordBindingType::INT64_TYPE, // end_at_timestamp + DBCommand::RecordBindingType::INT_TYPE, // daily_cap + DBCommand::RecordBindingType::STRING_TYPE, // advertiser_id + DBCommand::RecordBindingType::INT_TYPE, // priority + DBCommand::RecordBindingType::BOOL_TYPE, // conversion + DBCommand::RecordBindingType::INT_TYPE, // per_day + DBCommand::RecordBindingType::INT_TYPE, // total_max + DBCommand::RecordBindingType::STRING_TYPE, // segment + DBCommand::RecordBindingType::STRING_TYPE, // geo_target + DBCommand::RecordBindingType::STRING_TYPE, // target_url + DBCommand::RecordBindingType::STRING_TYPE, // title + DBCommand::RecordBindingType::STRING_TYPE, // description + 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(); + transaction->commands.push_back(std::move(command)); + + AdsClientHelper::Get()->RunDBTransaction(std::move(transaction), + std::bind(&CreativePromotedContentAds::OnGetAll, this, + std::placeholders::_1, callback)); +} + +void CreativePromotedContentAds::set_batch_size( + const int batch_size) { + DCHECK_GT(batch_size, 0); + + batch_size_ = batch_size; +} + +std::string CreativePromotedContentAds::get_table_name() const { + return kTableName; +} + +void CreativePromotedContentAds::Migrate( + DBTransaction* transaction, + const int to_version) { + DCHECK(transaction); + + switch (to_version) { + case 9: { + MigrateToV9(transaction); + break; + } + + default: { + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void CreativePromotedContentAds::InsertOrUpdate( + DBTransaction* transaction, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + DCHECK(transaction); + + if (creative_promoted_content_ads.empty()) { + return; + } + + DBCommandPtr command = DBCommand::New(); + command->type = DBCommand::Type::RUN; + command->command = BuildInsertOrUpdateQuery(command.get(), + creative_promoted_content_ads); + + transaction->commands.push_back(std::move(command)); +} + +int CreativePromotedContentAds::BindParameters( + DBCommand* command, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + DCHECK(command); + + int count = 0; + + int index = 0; + for (const auto& creative_promoted_content_ad : + creative_promoted_content_ads) { + BindString(command, index++, + creative_promoted_content_ad.creative_instance_id); + BindString(command, index++, creative_promoted_content_ad.creative_set_id); + BindString(command, index++, creative_promoted_content_ad.campaign_id); + BindString(command, index++, creative_promoted_content_ad.title); + BindString(command, index++, creative_promoted_content_ad.description); + + count++; + } + + return count; +} + +std::string CreativePromotedContentAds::BuildInsertOrUpdateQuery( + DBCommand* command, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + const int count = BindParameters(command, creative_promoted_content_ads); + + return base::StringPrintf( + "INSERT OR REPLACE INTO %s " + "(creative_instance_id, " + "creative_set_id, " + "campaign_id, " + "title, " + "description) VALUES %s", + get_table_name().c_str(), + BuildBindingParameterPlaceholders(5, count).c_str()); +} + +void CreativePromotedContentAds::OnGetForCreativeInstanceId( + DBCommandResponsePtr response, + const std::string& creative_instance_id, + GetCreativePromotedContentAdCallback callback) { + if (!response || response->status != DBCommandResponse::Status::RESPONSE_OK) { + BLOG(0, "Failed to get creative new tab page ad"); + callback(Result::FAILED, creative_instance_id, {}); + return; + } + + if (response->result->get_records().size() != 1) { + BLOG(0, "Failed to get creative new tab page ad"); + callback(Result::FAILED, creative_instance_id, {}); + return; + } + + DBRecord* record = response->result->get_records().at(0).get(); + + const CreativePromotedContentAdInfo creative_promoted_content_ad = + GetFromRecord(record); + + callback(Result::SUCCESS, creative_instance_id, creative_promoted_content_ad); +} + +void CreativePromotedContentAds::OnGetForSegments( + DBCommandResponsePtr response, + const SegmentList& segments, + GetCreativePromotedContentAdsCallback callback) { + if (!response || response->status != DBCommandResponse::Status::RESPONSE_OK) { + BLOG(0, "Failed to get creative new tab page ads"); + callback(Result::FAILED, segments, {}); + return; + } + + CreativePromotedContentAdList creative_promoted_content_ads; + + for (const auto& record : response->result->get_records()) { + const CreativePromotedContentAdInfo creative_promoted_content_ad = + GetFromRecord(record.get()); + + creative_promoted_content_ads.push_back(creative_promoted_content_ad); + } + + callback(Result::SUCCESS, segments, creative_promoted_content_ads); +} + +void CreativePromotedContentAds::OnGetAll( + DBCommandResponsePtr response, + GetCreativePromotedContentAdsCallback callback) { + if (!response || response->status != DBCommandResponse::Status::RESPONSE_OK) { + BLOG(0, "Failed to get all creative new tab page ads"); + callback(Result::FAILED, {}, {}); + return; + } + + CreativePromotedContentAdList creative_promoted_content_ads; + + SegmentList segments; + + for (const auto& record : response->result->get_records()) { + const CreativePromotedContentAdInfo creative_promoted_content_ad = + GetFromRecord(record.get()); + + creative_promoted_content_ads.push_back(creative_promoted_content_ad); + + segments.push_back(creative_promoted_content_ad.segment); + } + + std::sort(segments.begin(), segments.end()); + const auto iter = std::unique(segments.begin(), segments.end()); + segments.erase(iter, segments.end()); + + callback(Result::SUCCESS, segments, creative_promoted_content_ads); +} + +CreativePromotedContentAdInfo CreativePromotedContentAds::GetFromRecord( + DBRecord* record) const { + CreativePromotedContentAdInfo creative_promoted_content_ad; + + creative_promoted_content_ad.creative_instance_id = ColumnString(record, 0); + creative_promoted_content_ad.creative_set_id = ColumnString(record, 1); + creative_promoted_content_ad.campaign_id = ColumnString(record, 2); + creative_promoted_content_ad.start_at_timestamp = ColumnInt64(record, 3); + creative_promoted_content_ad.end_at_timestamp = ColumnInt64(record, 4); + creative_promoted_content_ad.daily_cap = ColumnInt(record, 5); + creative_promoted_content_ad.advertiser_id = ColumnString(record, 6); + creative_promoted_content_ad.priority = ColumnInt(record, 7); + creative_promoted_content_ad.conversion = ColumnBool(record, 8); + creative_promoted_content_ad.per_day = ColumnInt(record, 9); + creative_promoted_content_ad.total_max = ColumnInt(record, 10); + creative_promoted_content_ad.segment = ColumnString(record, 11); + creative_promoted_content_ad.geo_targets.push_back(ColumnString(record, 12)); + creative_promoted_content_ad.target_url = ColumnString(record, 13); + creative_promoted_content_ad.title = ColumnString(record, 14); + creative_promoted_content_ad.description = ColumnString(record, 15); + creative_promoted_content_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_promoted_content_ad.dayparts.push_back(daypart); + + return creative_promoted_content_ad; +} + +void CreativePromotedContentAds::CreateTableV9( + DBTransaction* transaction) { + DCHECK(transaction); + + const std::string query = base::StringPrintf( + "CREATE TABLE %s " + "(creative_instance_id TEXT NOT NULL PRIMARY KEY UNIQUE " + "ON CONFLICT REPLACE, " + "creative_set_id TEXT NOT NULL, " + "campaign_id TEXT NOT NULL, " + "title TEXT NOT NULL, " + "description TEXT NOT NULL)", + 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 CreativePromotedContentAds::MigrateToV9( + DBTransaction* transaction) { + DCHECK(transaction); + + util::Drop(transaction, get_table_name()); + + CreateTableV9(transaction); +} + +} // namespace table +} // namespace database +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table.h new file mode 100644 index 000000000000..28e0f2a5f6ed --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table.h @@ -0,0 +1,118 @@ +/* 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_CREATIVE_PROMOTED_CONTENT_ADS_DATABASE_TABLE_H_ // NOLINT +#define BAT_ADS_INTERNAL_DATABASE_CREATIVE_PROMOTED_CONTENT_ADS_DATABASE_TABLE_H_ // NOLINT + +#include +#include +#include + +#include "bat/ads/ads_client.h" +#include "bat/ads/internal/ad_targeting/ad_targeting.h" +#include "bat/ads/internal/bundle/creative_promoted_content_ad_info.h" +#include "bat/ads/internal/database/database_table.h" +#include "bat/ads/internal/database/tables/campaigns_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/internal/database/tables/segments_database_table.h" +#include "bat/ads/mojom.h" +#include "bat/ads/result.h" + +namespace ads { + +using GetCreativePromotedContentAdCallback = + std::function; + +using GetCreativePromotedContentAdsCallback = std::function&, const CreativePromotedContentAdList&)>; + +namespace database { +namespace table { + +class CreativePromotedContentAds : public Table { + public: + CreativePromotedContentAds(); + + ~CreativePromotedContentAds() override; + + void Save( + const CreativePromotedContentAdList& creative_promoted_content_ads, + ResultCallback callback); + + void Delete( + ResultCallback callback); + + void GetForCreativeInstanceId( + const std::string& creative_instance_id, + GetCreativePromotedContentAdCallback callback); + + void GetForSegments( + const SegmentList& segments, + GetCreativePromotedContentAdsCallback callback); + + void GetAll( + GetCreativePromotedContentAdsCallback callback); + + void set_batch_size( + const int batch_size); + + std::string get_table_name() const override; + + void Migrate( + DBTransaction* transaction, + const int to_version) override; + + private: + void InsertOrUpdate( + DBTransaction* transaction, + const CreativePromotedContentAdList& creative_promoted_content_ads); + + int BindParameters( + DBCommand* command, + const CreativePromotedContentAdList& creative_promoted_content_ads); + + std::string BuildInsertOrUpdateQuery( + DBCommand* command, + const CreativePromotedContentAdList& creative_promoted_content_ads); + + void OnGetForCreativeInstanceId( + DBCommandResponsePtr response, + const std::string& creative_instance_id, + GetCreativePromotedContentAdCallback callback); + + void OnGetForSegments( + DBCommandResponsePtr response, + const SegmentList& segments, + GetCreativePromotedContentAdsCallback callback); + + void OnGetAll( + DBCommandResponsePtr response, + GetCreativePromotedContentAdsCallback callback); + + CreativePromotedContentAdInfo GetFromRecord( + DBRecord* record) const; + + void CreateTableV9( + DBTransaction* transaction); + void MigrateToV9( + DBTransaction* transaction); + + int batch_size_; + + std::unique_ptr campaigns_database_table_; + std::unique_ptr creative_ads_database_table_; + std::unique_ptr dayparts_database_table_; + std::unique_ptr geo_targets_database_table_; + std::unique_ptr segments_database_table_; +}; + +} // namespace table +} // namespace database +} // namespace ads + +#endif // BAT_ADS_INTERNAL_DATABASE_CREATIVE_PROMOTED_CONTENT_ADS_DATABASE_TABLE_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_test.cc new file mode 100644 index 000000000000..66333d54db68 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_test.cc @@ -0,0 +1,63 @@ +/* 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/creative_promoted_content_ads_database_table.h" + +#include "net/http/http_status_code.h" +#include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_util.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +class BatAdsCreativePromotedContentAdsDatabaseTableIntegrationTest + : public UnitTestBase { + protected: + BatAdsCreativePromotedContentAdsDatabaseTableIntegrationTest() = default; + + ~BatAdsCreativePromotedContentAdsDatabaseTableIntegrationTest() + override = default; + + void SetUp() override { + UnitTestBase::SetUpForTesting(/* integration_test */ true); + } +}; + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableIntegrationTest, + GetCreativePromotedContentAdsFromCatalogEndpoint) { + // Arrange + const URLEndpoints endpoints = { + { + "/v6/catalog", { + { + net::HTTP_OK, "/catalog.json" + } + } + } + }; + + MockUrlRequest(ads_client_mock_, endpoints); + + InitializeAds(); + + // Act + + // Assert + const std::vector segments = { + "Technology & Computing" + }; + + database::table::CreativePromotedContentAds creative_promoted_content_ads; + creative_promoted_content_ads.GetForSegments(segments, []( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_EQ(1UL, creative_promoted_content_ads.size()); + }); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_unittest.cc new file mode 100644 index 000000000000..59e3210ca838 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_unittest.cc @@ -0,0 +1,753 @@ +/* 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/creative_promoted_content_ads_database_table.h" + +#include "bat/ads/internal/container_util.h" +#include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_util.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +class BatAdsCreativePromotedContentAdsDatabaseTableTest : public UnitTestBase { + protected: + BatAdsCreativePromotedContentAdsDatabaseTableTest() + : database_table_(std::make_unique< + database::table::CreativePromotedContentAds>()) { + } + + ~BatAdsCreativePromotedContentAdsDatabaseTableTest() override = default; + + void Save( + const CreativePromotedContentAdList creative_promoted_content_ads) { + database_table_->Save(creative_promoted_content_ads, []( + const Result result) { + ASSERT_EQ(Result::SUCCESS, result); + }); + } + + std::unique_ptr database_table_; +}; + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + SaveEmptyCreativePromotedContentAds) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads = {}; + + // Act + Save(creative_promoted_content_ads); + + // Assert +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + SaveCreativePromotedContentAds) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info_1; + info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info_1.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info_1.start_at_timestamp = DistantPast(); + info_1.end_at_timestamp = DistantFuture(); + info_1.daily_cap = 1; + info_1.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info_1.priority = 2; + info_1.per_day = 3; + info_1.total_max = 4; + info_1.segment = "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"; + info_1.description = "Test Ad 1 Body"; + info_1.ptr = 1.0; + creative_promoted_content_ads.push_back(info_1); + + CreativePromotedContentAdInfo info_2; + info_2.creative_instance_id = "eaa6224a-876d-4ef8-a384-9ac34f238631"; + info_2.creative_set_id = "184d1fdd-8e18-4baa-909c-9a3cb62cc7b1"; + info_2.campaign_id = "d1d4a649-502d-4e06-b4b8-dae11c382d26"; + info_2.start_at_timestamp = DistantPast(); + info_2.end_at_timestamp = DistantFuture(); + info_2.daily_cap = 1; + info_2.advertiser_id = "8e3fac86-ce50-4409-ae29-9aa5636aa9a2"; + info_2.priority = 2; + info_2.per_day = 3; + info_2.total_max = 4; + info_2.segment = "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"; + info_2.description = "Test Ad 2 Body"; + info_2.ptr = 0.8; + creative_promoted_content_ads.push_back(info_2); + + // Act + Save(creative_promoted_content_ads); + + // Assert + const CreativePromotedContentAdList expected_creative_promoted_content_ads = + creative_promoted_content_ads; + + const SegmentList segments = { + "Technology & Computing-Software" + }; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + SaveCreativePromotedContentAdsInBatches) { + // Arrange + database_table_->set_batch_size(2); + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativePromotedContentAdInfo info_1; + info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info_1.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info_1.start_at_timestamp = DistantPast(); + info_1.end_at_timestamp = DistantFuture(); + info_1.daily_cap = 1; + info_1.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info_1.priority = 2; + info_1.per_day = 3; + info_1.total_max = 4; + info_1.segment = "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"; + info_1.description = "Test Ad 1 Body"; + info_1.ptr = 1.0; + creative_promoted_content_ads.push_back(info_1); + + CreativePromotedContentAdInfo info_2; + info_2.creative_instance_id = "eaa6224a-876d-4ef8-a384-9ac34f238631"; + info_2.creative_set_id = "184d1fdd-8e18-4baa-909c-9a3cb62cc7b1"; + info_2.campaign_id = "d1d4a649-502d-4e06-b4b8-dae11c382d26"; + info_2.start_at_timestamp = DistantPast(); + info_2.end_at_timestamp = DistantFuture(); + info_2.daily_cap = 1; + info_2.advertiser_id = "8e3fac86-ce50-4409-ae29-9aa5636aa9a2"; + info_2.priority = 2; + info_2.per_day = 3; + info_2.total_max = 4; + info_2.segment = "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"; + info_2.description = "Test Ad 2 Body"; + info_2.ptr = 1.0; + creative_promoted_content_ads.push_back(info_2); + + CreativePromotedContentAdInfo info_3; + info_3.creative_instance_id = "a1ac44c2-675f-43e6-ab6d-500614cafe63"; + info_3.creative_set_id = "5800049f-cee5-4bcb-90c7-85246d5f5e7c"; + info_3.campaign_id = "3d62eca2-324a-4161-a0c5-7d9f29d10ab0"; + info_3.start_at_timestamp = DistantPast(); + info_3.end_at_timestamp = DistantFuture(); + info_3.daily_cap = 1; + info_3.advertiser_id = "9a11b60f-e29d-4446-8d1f-318311e36e0a"; + info_3.priority = 2; + info_3.per_day = 3; + info_3.total_max = 4; + info_3.segment = "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"; + info_3.description = "Test Ad 3 Body"; + info_3.ptr = 1.0; + creative_promoted_content_ads.push_back(info_3); + + // Act + Save(creative_promoted_content_ads); + + // Assert + const CreativePromotedContentAdList expected_creative_promoted_content_ads = + creative_promoted_content_ads; + + const SegmentList segments = { + "Technology & Computing-Software" + }; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + DoNotSaveDuplicateCreativePromotedContentAds) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info; + info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info.start_at_timestamp = DistantPast(); + info.end_at_timestamp = DistantFuture(); + info.daily_cap = 1; + info.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info.priority = 2; + info.per_day = 3; + info.total_max = 4; + info.segment = "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"; + info.description = "Test Ad 1 Body"; + info.ptr = 1.0; + creative_promoted_content_ads.push_back(info); + + Save(creative_promoted_content_ads); + + // Act + Save(creative_promoted_content_ads); + + // Assert + const CreativePromotedContentAdList expected_creative_promoted_content_ads = + creative_promoted_content_ads; + + const SegmentList segments = { + "Technology & Computing-Software" + }; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + GetForCategories) { + // Arrange + + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info_1; + info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info_1.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info_1.start_at_timestamp = DistantPast(); + info_1.end_at_timestamp = DistantFuture(); + info_1.daily_cap = 1; + info_1.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info_1.priority = 2; + info_1.per_day = 3; + info_1.total_max = 4; + info_1.segment = "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"; + info_1.description = "Test Ad 1 Body"; + info_1.ptr = 1.0; + creative_promoted_content_ads.push_back(info_1); + + CreativePromotedContentAdInfo info_2; + info_2.creative_instance_id = "eaa6224a-876d-4ef8-a384-9ac34f238631"; + info_2.creative_set_id = "184d1fdd-8e18-4baa-909c-9a3cb62cc7b1"; + info_2.campaign_id = "d1d4a649-502d-4e06-b4b8-dae11c382d26"; + info_2.start_at_timestamp = DistantPast(); + info_2.end_at_timestamp = DistantFuture(); + info_2.daily_cap = 1; + info_2.advertiser_id = "8e3fac86-ce50-4409-ae29-9aa5636aa9a2"; + info_2.priority = 2; + info_2.per_day = 3; + info_2.total_max = 4; + info_2.segment = "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"; + info_2.description = "Test Ad 2 Body"; + info_2.ptr = 1.0; + creative_promoted_content_ads.push_back(info_2); + + Save(creative_promoted_content_ads); + + // Act + + // Assert + const CreativePromotedContentAdList expected_creative_promoted_content_ads = + creative_promoted_content_ads; + + const SegmentList segments = { + "Technology & Computing-Software" + }; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + GetCreativePromotedContentAdsForCreativeInstanceId) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info; + info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info.start_at_timestamp = DistantPast(); + info.end_at_timestamp = DistantFuture(); + info.daily_cap = 1; + info.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info.priority = 2; + info.per_day = 3; + info.total_max = 4; + info.segment = "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"; + info.description = "Test Ad 1 Body"; + info.ptr = 1.0; + creative_promoted_content_ads.push_back(info); + + Save(creative_promoted_content_ads); + + // Act + + // Assert + const CreativePromotedContentAdInfo expected_creative_promoted_content_ad = + info; + + const std::string creative_instance_id = + "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + + database_table_->GetForCreativeInstanceId(creative_instance_id, + [&expected_creative_promoted_content_ad]( + const Result result, + const std::string& creative_instance_id, + const CreativePromotedContentAdInfo& creative_promoted_content_ad) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_EQ(expected_creative_promoted_content_ad, + creative_promoted_content_ad); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + GetCreativePromotedContentAdsForNonExistentCreativeInstanceId) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info; + info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info.start_at_timestamp = DistantPast(); + info.end_at_timestamp = DistantFuture(); + info.daily_cap = 1; + info.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info.priority = 2; + info.per_day = 3; + info.total_max = 4; + info.segment = "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"; + info.description = "Test Ad 1 Body"; + info.ptr = 1.0; + creative_promoted_content_ads.push_back(info); + + Save(creative_promoted_content_ads); + + // Act + + // Assert + const std::string creative_instance_id = + "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; + + database_table_->GetForCreativeInstanceId(creative_instance_id, []( + const Result result, + const std::string& creative_instance_id, + const CreativePromotedContentAdInfo& creative_promoted_content_ad) { + EXPECT_EQ(Result::FAILED, result); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + GetCreativePromotedContentAdsForEmptyCategories) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info; + info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info.start_at_timestamp = DistantPast(); + info.end_at_timestamp = DistantFuture(); + info.daily_cap = 1; + info.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info.priority = 2; + info.per_day = 3; + info.total_max = 4; + info.segment = "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"; + info.description = "Test Ad 1 Body"; + info.ptr = 1.0; + creative_promoted_content_ads.push_back(info); + + Save(creative_promoted_content_ads); + + // Act + + // Assert + const CreativePromotedContentAdList + expected_creative_promoted_content_ads = {}; + + const SegmentList segments = {}; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + GetCreativePromotedContentAdsForNonExistentCategory) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info; + info.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info.start_at_timestamp = DistantPast(); + info.end_at_timestamp = DistantFuture(); + info.daily_cap = 1; + info.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info.priority = 2; + info.per_day = 3; + info.total_max = 4; + info.segment = "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"; + info.description = "Test Ad 1 Body"; + info.ptr = 1.0; + creative_promoted_content_ads.push_back(info); + + Save(creative_promoted_content_ads); + + // Act + + // Assert + const CreativePromotedContentAdList + expected_creative_promoted_content_ads = {}; + + const SegmentList segments = { + "Food & Drink" + }; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + GetCreativePromotedContentAdsFromMultipleCategories) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info_1; + info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info_1.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info_1.start_at_timestamp = DistantPast(); + info_1.end_at_timestamp = DistantFuture(); + info_1.daily_cap = 1; + info_1.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info_1.priority = 2; + info_1.per_day = 3; + info_1.total_max = 4; + info_1.segment = "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"; + info_1.description = "Test Ad 1 Body"; + info_1.ptr = 1.0; + creative_promoted_content_ads.push_back(info_1); + + CreativePromotedContentAdInfo info_2; + info_2.creative_instance_id = "eaa6224a-876d-4ef8-a384-9ac34f238631"; + info_2.creative_set_id = "184d1fdd-8e18-4baa-909c-9a3cb62cc7b1"; + info_2.campaign_id = "d1d4a649-502d-4e06-b4b8-dae11c382d26"; + info_2.start_at_timestamp = DistantPast(); + info_2.end_at_timestamp = DistantFuture(); + info_2.daily_cap = 1; + info_2.advertiser_id = "8e3fac86-ce50-4409-ae29-9aa5636aa9a2"; + info_2.priority = 2; + info_2.per_day = 3; + info_2.total_max = 4; + info_2.segment = "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"; + info_2.description = "Test Ad 2 Body"; + info_2.ptr = 1.0; + creative_promoted_content_ads.push_back(info_2); + + CreativePromotedContentAdInfo info_3; + info_3.creative_instance_id = "a1ac44c2-675f-43e6-ab6d-500614cafe63"; + info_3.creative_set_id = "5800049f-cee5-4bcb-90c7-85246d5f5e7c"; + info_3.campaign_id = "3d62eca2-324a-4161-a0c5-7d9f29d10ab0"; + info_3.start_at_timestamp = DistantPast(); + info_3.end_at_timestamp = DistantFuture(); + info_3.daily_cap = 1; + info_3.advertiser_id = "9a11b60f-e29d-4446-8d1f-318311e36e0a"; + info_3.priority = 2; + info_3.per_day = 3; + info_3.total_max = 4; + info_3.segment = "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"; + info_3.description = "Test Ad 3 Body"; + info_3.ptr = 1.0; + creative_promoted_content_ads.push_back(info_3); + + Save(creative_promoted_content_ads); + + // Act + + // Assert + CreativePromotedContentAdList expected_creative_promoted_content_ads; + expected_creative_promoted_content_ads.push_back(info_1); + expected_creative_promoted_content_ads.push_back(info_2); + + const SegmentList segments = { + "Technology & Computing-Software", + "Food & Drink" + }; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + GetNonExpiredCreativePromotedContentAds) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info_1; + info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info_1.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info_1.start_at_timestamp = DistantPast(); + info_1.end_at_timestamp = Now(); + info_1.daily_cap = 1; + info_1.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info_1.priority = 2; + info_1.per_day = 3; + info_1.total_max = 4; + info_1.segment = "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"; + info_1.description = "Test Ad 1 Body"; + info_1.ptr = 1.0; + creative_promoted_content_ads.push_back(info_1); + + CreativePromotedContentAdInfo info_2; + info_2.creative_instance_id = "eaa6224a-876d-4ef8-a384-9ac34f238631"; + info_2.creative_set_id = "184d1fdd-8e18-4baa-909c-9a3cb62cc7b1"; + info_2.campaign_id = "d1d4a649-502d-4e06-b4b8-dae11c382d26"; + info_2.start_at_timestamp = DistantPast(); + info_2.end_at_timestamp = DistantFuture(); + info_2.daily_cap = 1; + info_2.advertiser_id = "8e3fac86-ce50-4409-ae29-9aa5636aa9a2"; + info_2.priority = 2; + info_2.per_day = 3; + info_2.total_max = 4; + info_2.segment = "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"; + info_2.description = "Test Ad 2 Body"; + info_2.ptr = 1.0; + creative_promoted_content_ads.push_back(info_2); + + Save(creative_promoted_content_ads); + + // Act + FastForwardClockBy(base::TimeDelta::FromHours(1)); + + // Assert + CreativePromotedContentAdList expected_creative_promoted_content_ads; + expected_creative_promoted_content_ads.push_back(info_2); + + const SegmentList segments = { + "Technology & Computing-Software" + }; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + GetCreativePromotedContentAdsMatchingCaseInsensitiveCategories) { + // Arrange + CreativePromotedContentAdList creative_promoted_content_ads; + + CreativeDaypartInfo daypart_info; + CreativePromotedContentAdInfo info_1; + info_1.creative_instance_id = "3519f52c-46a4-4c48-9c2b-c264c0067f04"; + info_1.creative_set_id = "c2ba3e7d-f688-4bc4-a053-cbe7ac1e6123"; + info_1.campaign_id = "84197fc8-830a-4a8e-8339-7a70c2bfa104"; + info_1.start_at_timestamp = DistantPast(); + info_1.end_at_timestamp = DistantFuture(); + info_1.daily_cap = 1; + info_1.advertiser_id = "5484a63f-eb99-4ba5-a3b0-8c25d3c0e4b2"; + info_1.priority = 2; + info_1.per_day = 3; + info_1.total_max = 4; + info_1.segment = "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"; + info_1.description = "Test Ad 1 Body"; + info_1.ptr = 1.0; + creative_promoted_content_ads.push_back(info_1); + + CreativePromotedContentAdInfo info_2; + info_2.creative_instance_id = "a1ac44c2-675f-43e6-ab6d-500614cafe63"; + info_2.creative_set_id = "5800049f-cee5-4bcb-90c7-85246d5f5e7c"; + info_2.campaign_id = "3d62eca2-324a-4161-a0c5-7d9f29d10ab0"; + info_2.start_at_timestamp = DistantPast(); + info_2.end_at_timestamp = DistantFuture(); + info_2.daily_cap = 1; + info_2.advertiser_id = "9a11b60f-e29d-4446-8d1f-318311e36e0a"; + info_2.priority = 2; + info_2.per_day = 3; + info_2.total_max = 4; + info_2.segment = "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"; + info_2.description = "Test Ad 2 Body"; + info_2.ptr = 1.0; + creative_promoted_content_ads.push_back(info_2); + + Save(creative_promoted_content_ads); + + // Act + + // Assert + CreativePromotedContentAdList expected_creative_promoted_content_ads; + expected_creative_promoted_content_ads.push_back(info_2); + + const SegmentList segments = { + "FoOd & DrInK" + }; + + database_table_->GetForSegments(segments, + [&expected_creative_promoted_content_ads]( + const Result result, + const SegmentList& segments, + const CreativePromotedContentAdList& creative_promoted_content_ads) { + EXPECT_EQ(Result::SUCCESS, result); + EXPECT_TRUE(CompareAsSets(expected_creative_promoted_content_ads, + creative_promoted_content_ads)); + }); +} + +TEST_F(BatAdsCreativePromotedContentAdsDatabaseTableTest, + TableName) { + // Arrange + + // Act + const std::string table_name = database_table_->get_table_name(); + + // Assert + const std::string expected_table_name = "creative_promoted_content_ads"; + EXPECT_EQ(expected_table_name, table_name); +} + +} // namespace ads 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 index ddac67a34662..c37ed9322bd9 100644 --- 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 @@ -66,8 +66,8 @@ void Dayparts::Migrate( DCHECK(transaction); switch (to_version) { - case 8: { - MigrateToV8(transaction); + case 9: { + MigrateToV9(transaction); break; } @@ -117,7 +117,7 @@ std::string Dayparts::BuildInsertOrUpdateQuery( BuildBindingParameterPlaceholders(4, count).c_str()); } -void Dayparts::CreateTableV8( +void Dayparts::CreateTableV9( DBTransaction* transaction) { DCHECK(transaction); @@ -139,13 +139,13 @@ void Dayparts::CreateTableV8( transaction->commands.push_back(std::move(command)); } -void Dayparts::MigrateToV8( +void Dayparts::MigrateToV9( DBTransaction* transaction) { DCHECK(transaction); util::Drop(transaction, get_table_name()); - CreateTableV8(transaction); + CreateTableV9(transaction); } } // namespace table 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 index b4a88711cfe7..062bec44df42 100644 --- 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 @@ -45,9 +45,9 @@ class Dayparts : public Table { DBCommand* command, const CreativeAdList& creative_ads); - void CreateTableV8( + void CreateTableV9( DBTransaction* transaction); - void MigrateToV8( + void MigrateToV9( DBTransaction* transaction); }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/geo_targets_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/geo_targets_database_table.cc index 06531230fe66..5e1e177623cd 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/geo_targets_database_table.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/geo_targets_database_table.cc @@ -62,8 +62,8 @@ void GeoTargets::Migrate( DCHECK(transaction); switch (to_version) { - case 8: { - MigrateToV8(transaction); + case 9: { + MigrateToV9(transaction); break; } @@ -108,7 +108,7 @@ std::string GeoTargets::BuildInsertOrUpdateQuery( BuildBindingParameterPlaceholders(2, count).c_str()); } -void GeoTargets::CreateTableV8( +void GeoTargets::CreateTableV9( DBTransaction* transaction) { DCHECK(transaction); @@ -127,13 +127,13 @@ void GeoTargets::CreateTableV8( transaction->commands.push_back(std::move(command)); } -void GeoTargets::MigrateToV8( +void GeoTargets::MigrateToV9( DBTransaction* transaction) { DCHECK(transaction); util::Drop(transaction, get_table_name()); - CreateTableV8(transaction); + CreateTableV9(transaction); } } // namespace table diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/geo_targets_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/geo_targets_database_table.h index 548cbf3b182c..3812b54af1c8 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/geo_targets_database_table.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/geo_targets_database_table.h @@ -45,9 +45,9 @@ class GeoTargets : public Table { DBCommand* command, const CreativeAdList& creative_ads); - void CreateTableV8( + void CreateTableV9( DBTransaction* transaction); - void MigrateToV8( + void MigrateToV9( DBTransaction* transaction); }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table.cc index e4aad69b8058..f81af2f6277c 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table.cc @@ -63,8 +63,8 @@ void Segments::Migrate( DCHECK(transaction); switch (to_version) { - case 8: { - MigrateToV8(transaction); + case 9: { + MigrateToV9(transaction); break; } @@ -107,7 +107,7 @@ std::string Segments::BuildInsertOrUpdateQuery( BuildBindingParameterPlaceholders(2, count).c_str()); } -void Segments::CreateTableV8( +void Segments::CreateTableV9( DBTransaction* transaction) { DCHECK(transaction); @@ -126,13 +126,13 @@ void Segments::CreateTableV8( transaction->commands.push_back(std::move(command)); } -void Segments::MigrateToV8( +void Segments::MigrateToV9( DBTransaction* transaction) { DCHECK(transaction); util::Drop(transaction, "categories"); - CreateTableV8(transaction); + CreateTableV9(transaction); } } // namespace table diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table.h index 2c7195769425..abe174ca8c52 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table.h @@ -45,9 +45,9 @@ class Segments : public Table { DBCommand* command, const CreativeAdList& creative_ads); - void CreateTableV8( + void CreateTableV9( DBTransaction* transaction); - void MigrateToV8( + void MigrateToV9( DBTransaction* transaction); }; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap.cc index d0cada67cbef..67da855407a7 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap.cc @@ -76,9 +76,9 @@ AdEventList ConversionFrequencyCap::FilterAdEvents( const auto iter = std::remove_if(filtered_ad_events.begin(), filtered_ad_events.end(), [&ad](const AdEventInfo& ad_event) { - return ad_event.type == AdType::kNewTabPageAd || + return ad_event.type != AdType::kAdNotification || ad_event.creative_set_id != ad.creative_set_id || - ad_event.confirmation_type != ConfirmationType::kConversion; + ad_event.confirmation_type != ConfirmationType::kConversion; }); filtered_ad_events.erase(iter, filtered_ad_events.end()); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap_unittest.cc index 89a3841f609d..1c6628259df6 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/conversion_frequency_cap_unittest.cc @@ -49,7 +49,7 @@ TEST_F(BatAdsConversionFrequencyCapTest, } TEST_F(BatAdsConversionFrequencyCapTest, - DoNotAllowAdIfShouldNotAllowConversionTrackingAndHasAConversion) { + DoNotAllowAdIfShouldNotAllowConversionTracking) { // Arrange ads_client_mock_->SetBooleanPref( prefs::kShouldAllowConversionTracking, false); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap.cc index 9e6d779aba9f..f0f4392bf976 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap.cc @@ -62,7 +62,7 @@ AdEventList DailyCapFrequencyCap::FilterAdEvents( const auto iter = std::remove_if(filtered_ad_events.begin(), filtered_ad_events.end(), [&ad](const AdEventInfo& ad_event) { - return ad_event.type == AdType::kNewTabPageAd || + return ad_event.type != AdType::kAdNotification || ad_event.campaign_id != ad.campaign_id || ad_event.confirmation_type != ConfirmationType::kViewed; }); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap_unittest.cc index a65a6f3d17c2..c3e76f7c151b 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/daily_cap_frequency_cap_unittest.cc @@ -70,6 +70,35 @@ TEST_F(BatAdsDailyCapFrequencyCapTest, EXPECT_FALSE(should_exclude); } +TEST_F(BatAdsDailyCapFrequencyCapTest, + AllowAdIfDoesNotExceedCapForMultipleTypes) { + // Arrange + CreativeAdInfo ad; + ad.campaign_id = kCampaignIds.at(0); + ad.daily_cap = 2; + + AdEventList ad_events; + + const AdEventInfo ad_event_1 = GenerateAdEvent(AdType::kAdNotification, ad, + ConfirmationType::kViewed); + ad_events.push_back(ad_event_1); + + const AdEventInfo ad_event_2 = GenerateAdEvent(AdType::kNewTabPageAd, ad, + ConfirmationType::kViewed); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_3 = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + ad_events.push_back(ad_event_3); + + // Act + DailyCapFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + TEST_F(BatAdsDailyCapFrequencyCapTest, AllowAdIfDoesNotExceedCapForNoMatchingCampaigns) { // Arrange diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap.cc index d17bef2f4d7a..0d12aa6c5329 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap.cc @@ -71,7 +71,7 @@ AdEventList DismissedFrequencyCap::FilterAdEvents( const auto iter = std::remove_if(filtered_ad_events.begin(), filtered_ad_events.end(), [&ad, now](const AdEventInfo& ad_event) { - return ad_event.type == AdType::kNewTabPageAd || + return ad_event.type != AdType::kAdNotification || ad_event.campaign_id != ad.campaign_id || now - ad_event.timestamp >= time_constraint; }); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap_unittest.cc index 1f66ddf351f4..bca4e62f48c8 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/dismissed_frequency_cap_unittest.cc @@ -83,6 +83,35 @@ TEST_F(BatAdsDismissedFrequencyCapTest, EXPECT_FALSE(should_exclude); } +TEST_F(BatAdsDismissedFrequencyCapTest, + AdAllowedForAdWithSameCampaignIdWithin48HoursIfDismissedForMultipleTypes) { + // Arrange + CreativeAdInfo ad; + ad.creative_instance_id = kCreativeInstanceId; + ad.campaign_id = kCampaignIds.at(0); + + AdEventList ad_events; + + const AdEventInfo ad_event_1 = GenerateAdEvent(AdType::kAdNotification, ad, + ConfirmationType::kDismissed); + ad_events.push_back(ad_event_1); + + const AdEventInfo ad_event_2 = GenerateAdEvent(AdType::kNewTabPageAd, ad, + ConfirmationType::kDismissed); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_3 = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kDismissed); + ad_events.push_back(ad_event_3); + + // Act + DismissedFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + TEST_F(BatAdsDismissedFrequencyCapTest, AdAllowedForAdWithSameCampaignIdWithin48HoursIfDismissedThenClicked) { // Arrange diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/new_tab_page_ad_uuid_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/new_tab_page_ad_uuid_frequency_cap_unittest.cc index 9bcafe1beaf6..45d7a1d8915c 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/new_tab_page_ad_uuid_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/new_tab_page_ad_uuid_frequency_cap_unittest.cc @@ -71,6 +71,37 @@ TEST_F(BatAdsNewTabPageAdUuidFrequencyCapTest, EXPECT_FALSE(should_exclude); } +TEST_F(BatAdsNewTabPageAdUuidFrequencyCapTest, + AdAllowedForAdWithDifferentUuidForMultipleTypes) { + // Arrange + AdInfo ad_1; + ad_1.uuid = kUuids.at(0); + + AdInfo ad_2; + ad_2.uuid = kUuids.at(1); + + AdEventList ad_events; + + const AdEventInfo ad_event_1 = GenerateAdEvent(AdType::kAdNotification, + ad_2, ConfirmationType::kViewed); + ad_events.push_back(ad_event_1); + + const AdEventInfo ad_event_2 = GenerateAdEvent(AdType::kNewTabPageAd, + ad_2, ConfirmationType::kViewed); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_3 = GenerateAdEvent(AdType::kPromotedContentAd, + ad_2, ConfirmationType::kViewed); + ad_events.push_back(ad_event_3); + + // Act + NewTabPageAdUuidFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad_1); + + // Assert + EXPECT_FALSE(should_exclude); +} + TEST_F(BatAdsNewTabPageAdUuidFrequencyCapTest, AdNotAllowedForAdWithSameUuid) { // Arrange diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap.cc index 7c83ecd2370f..80d04f3acf7e 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap.cc @@ -62,7 +62,7 @@ AdEventList PerDayFrequencyCap::FilterAdEvents( const auto iter = std::remove_if(filtered_ad_events.begin(), filtered_ad_events.end(), [&ad](const AdEventInfo& ad_event) { - return ad_event.type == AdType::kNewTabPageAd || + return ad_event.type != AdType::kAdNotification || ad_event.creative_set_id != ad.creative_set_id || ad_event.confirmation_type != ConfirmationType::kViewed; }); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap_unittest.cc index 63fd83f461fc..d7c3a1b89f29 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_day_frequency_cap_unittest.cc @@ -63,6 +63,35 @@ TEST_F(BatAdsPerDayFrequencyCapTest, EXPECT_FALSE(should_exclude); } +TEST_F(BatAdsPerDayFrequencyCapTest, + AllowAdIfDoesNotExceedCapForMultipleTypes) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetId; + ad.per_day = 2; + + AdEventList ad_events; + + AdEventInfo ad_event_1 = GenerateAdEvent(AdType::kAdNotification, ad, + ConfirmationType::kViewed); + ad_events.push_back(ad_event_1); + + AdEventInfo ad_event_2 = GenerateAdEvent(AdType::kNewTabPageAd, ad, + ConfirmationType::kViewed); + ad_events.push_back(ad_event_2); + + AdEventInfo ad_event_3 = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + ad_events.push_back(ad_event_3); + + // Act + PerDayFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + TEST_F(BatAdsPerDayFrequencyCapTest, AllowAdIfDoesNotExceedCapAfter1Day) { // Arrange diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap.cc index 8c842bd6528e..5033eab86e76 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap.cc @@ -65,7 +65,7 @@ AdEventList PerHourFrequencyCap::FilterAdEvents( const auto iter = std::remove_if(filtered_ad_events.begin(), filtered_ad_events.end(), [&ad](const AdEventInfo& ad_event) { - return ad_event.type == AdType::kNewTabPageAd || + return ad_event.type != AdType::kAdNotification || ad_event.creative_instance_id != ad.creative_instance_id || ad_event.confirmation_type != ConfirmationType::kViewed; }); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap_unittest.cc index 7cf573600644..ede477d3de4e 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/per_hour_frequency_cap_unittest.cc @@ -63,6 +63,36 @@ TEST_F(BatAdsPerHourFrequencyCapTest, EXPECT_FALSE(should_exclude); } +TEST_F(BatAdsPerHourFrequencyCapTest, + AdAllowedAfter1HourForMultipleTypes) { + // Arrange + CreativeAdInfo ad; + ad.creative_instance_id = kCreativeInstanceId; + + AdEventList ad_events; + + const AdEventInfo ad_event_1 = GenerateAdEvent(AdType::kAdNotification, + ad, ConfirmationType::kViewed); + ad_events.push_back(ad_event_1); + + const AdEventInfo ad_event_2 = GenerateAdEvent(AdType::kNewTabPageAd, + ad, ConfirmationType::kViewed); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_3 = GenerateAdEvent(AdType::kPromotedContentAd, + ad, ConfirmationType::kViewed); + ad_events.push_back(ad_event_3); + + FastForwardClockBy(base::TimeDelta::FromHours(1)); + + // Act + PerHourFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + TEST_F(BatAdsPerHourFrequencyCapTest, DoNotAllowTheSameAdWithin1Hour) { // Arrange diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.cc new file mode 100644 index 000000000000..718468bbef79 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.cc @@ -0,0 +1,71 @@ +/* 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/promoted_content_ad_uuid_frequency_cap.h" + +#include + +#include "base/strings/stringprintf.h" +#include "bat/ads/ad_info.h" +#include "bat/ads/internal/logging.h" + +namespace ads { + +namespace { +const uint64_t kPromotedContentAdUuidFrequencyCap = 1; +} // namespace + +PromotedContentAdUuidFrequencyCap::PromotedContentAdUuidFrequencyCap( + const AdEventList& ad_events) + : ad_events_(ad_events) { +} + +PromotedContentAdUuidFrequencyCap:: +~PromotedContentAdUuidFrequencyCap() = default; + +bool PromotedContentAdUuidFrequencyCap::ShouldExclude( + const AdInfo& ad) { + const AdEventList filtered_ad_events = FilterAdEvents(ad_events_, ad); + + if (!DoesRespectCap(filtered_ad_events)) { + last_message_ = base::StringPrintf("uuid %s has exceeded the " + "frequency capping for new tab page ad", ad.uuid.c_str()); + return true; + } + + return false; +} + +std::string PromotedContentAdUuidFrequencyCap::get_last_message() const { + return last_message_; +} + +bool PromotedContentAdUuidFrequencyCap::DoesRespectCap( + const AdEventList& ad_events) { + if (ad_events.size() >= kPromotedContentAdUuidFrequencyCap) { + return false; + } + + return true; +} + +AdEventList PromotedContentAdUuidFrequencyCap::FilterAdEvents( + const AdEventList& ad_events, + const AdInfo& ad) const { + AdEventList filtered_ad_events = ad_events; + + const auto iter = std::remove_if(filtered_ad_events.begin(), + filtered_ad_events.end(), [&ad](const AdEventInfo& ad_event) { + return ad_event.uuid != ad.uuid || + ad_event.confirmation_type != ConfirmationType::kViewed || + ad_event.type != AdType::kPromotedContentAd; + }); + + filtered_ad_events.erase(iter, filtered_ad_events.end()); + + return filtered_ad_events; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.h b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.h new file mode 100644 index 000000000000..cf0b9c2ae2f1 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.h @@ -0,0 +1,50 @@ +/* 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_AD_EXCLUSION_RULES_PROMOTED_CONTENT_AD_UUID_FREQUENCY_CAP_H_ // NOLINT +#define BAT_ADS_INTERNAL_FREQUENCY_CAPPING_AD_EXCLUSION_RULES_PROMOTED_CONTENT_AD_UUID_FREQUENCY_CAP_H_ // NOLINT + +#include + +#include "bat/ads/internal/ad_events/ad_event_info.h" +#include "bat/ads/internal/frequency_capping/exclusion_rules/exclusion_rule.h" + +namespace ads { + +struct AdInfo; + +class PromotedContentAdUuidFrequencyCap : public ExclusionRule { + public: + PromotedContentAdUuidFrequencyCap( + const AdEventList& ad_events); + + ~PromotedContentAdUuidFrequencyCap() override; + + PromotedContentAdUuidFrequencyCap( + const PromotedContentAdUuidFrequencyCap&) = delete; + PromotedContentAdUuidFrequencyCap& operator=( + const PromotedContentAdUuidFrequencyCap&) = delete; + + bool ShouldExclude( + const AdInfo& ad) override; + + std::string get_last_message() const override; + + private: + AdEventList ad_events_; + + std::string last_message_; + + bool DoesRespectCap( + const AdEventList& ad_events); + + AdEventList FilterAdEvents( + const AdEventList& ad_events, + const AdInfo& ad) const; +}; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_FREQUENCY_CAPPING_AD_EXCLUSION_RULES_PROMOTED_CONTENT_AD_UUID_FREQUENCY_CAP_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap_unittest.cc new file mode 100644 index 000000000000..1b2dec869764 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap_unittest.cc @@ -0,0 +1,126 @@ +/* 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/promoted_content_ad_uuid_frequency_cap.h" + +#include + +#include "bat/ads/internal/frequency_capping/frequency_capping_unittest_util.h" +#include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_util.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +namespace { + +const std::vector kUuids = { + "60267cee-d5bb-4a0d-baaf-91cd7f18e07e", + "90762cee-d5bb-4a0d-baaf-61cd7f18e07e" +}; + +} // namespace + +class BatAdsPromotedContentAdUuidFrequencyCapTest : public UnitTestBase{ + protected: + BatAdsPromotedContentAdUuidFrequencyCapTest() = default; + + ~BatAdsPromotedContentAdUuidFrequencyCapTest() override = default; +}; + +TEST_F(BatAdsPromotedContentAdUuidFrequencyCapTest, + AllowAdIfThereIsNoAdsHistory) { + // Arrange + AdInfo ad; + ad.uuid = kUuids.at(0); + + const AdEventList ad_events; + + // Act + PromotedContentAdUuidFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + +TEST_F(BatAdsPromotedContentAdUuidFrequencyCapTest, + AdAllowedForAdWithDifferentUuid) { + // Arrange + AdInfo ad_1; + ad_1.uuid = kUuids.at(0); + + AdInfo ad_2; + ad_2.uuid = kUuids.at(1); + + AdEventList ad_events; + + const AdEventInfo ad_event = GenerateAdEvent(AdType::kPromotedContentAd, ad_2, + ConfirmationType::kViewed); + + ad_events.push_back(ad_event); + + // Act + PromotedContentAdUuidFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad_1); + + // Assert + EXPECT_FALSE(should_exclude); +} + +TEST_F(BatAdsPromotedContentAdUuidFrequencyCapTest, + AdAllowedForAdWithDifferentUuidForMultipleTypes) { + // Arrange + AdInfo ad_1; + ad_1.uuid = kUuids.at(0); + + AdInfo ad_2; + ad_2.uuid = kUuids.at(1); + + AdEventList ad_events; + + const AdEventInfo ad_event_1 = GenerateAdEvent(AdType::kNewTabPageAd, + ad_2, ConfirmationType::kViewed); + ad_events.push_back(ad_event_1); + + const AdEventInfo ad_event_2 = GenerateAdEvent(AdType::kPromotedContentAd, + ad_2, ConfirmationType::kViewed); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_3 = GenerateAdEvent(AdType::kPromotedContentAd, + ad_2, ConfirmationType::kViewed); + ad_events.push_back(ad_event_3); + + // Act + PromotedContentAdUuidFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad_1); + + // Assert + EXPECT_FALSE(should_exclude); +} + +TEST_F(BatAdsPromotedContentAdUuidFrequencyCapTest, + AdNotAllowedForAdWithSameUuid) { + // Arrange + AdInfo ad; + ad.uuid = kUuids.at(0); + + AdEventList ad_events; + + const AdEventInfo ad_event = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + + ad_events.push_back(ad_event); + + // Act + PromotedContentAdUuidFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad); + + // Assert + EXPECT_TRUE(should_exclude); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap.cc index 7d33e1189a5d..297ca13104df 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap.cc @@ -53,7 +53,7 @@ AdEventList TotalMaxFrequencyCap::FilterAdEvents( const auto iter = std::remove_if(filtered_ad_events.begin(), filtered_ad_events.end(), [&ad](const AdEventInfo& ad_event) { - return ad_event.type == AdType::kNewTabPageAd || + return ad_event.type != AdType::kAdNotification || ad_event.creative_set_id != ad.creative_set_id || ad_event.confirmation_type != ConfirmationType::kViewed; }); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap_unittest.cc index 1c455114302f..ca509770d179 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/total_max_frequency_cap_unittest.cc @@ -70,6 +70,35 @@ TEST_F(BatAdsTotalMaxFrequencyCapTest, EXPECT_FALSE(should_exclude); } +TEST_F(BatAdsTotalMaxFrequencyCapTest, + AllowAdIfDoesNotExceedCapForMultipleTypes) { + // Arrange + CreativeAdInfo ad; + ad.creative_set_id = kCreativeSetIds.at(0); + ad.total_max = 2; + + AdEventList ad_events; + + const AdEventInfo ad_event_1 = GenerateAdEvent(AdType::kAdNotification, + ad, ConfirmationType::kViewed); + ad_events.push_back(ad_event_1); + + const AdEventInfo ad_event_2 = GenerateAdEvent(AdType::kNewTabPageAd, + ad, ConfirmationType::kViewed); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_3 = GenerateAdEvent(AdType::kPromotedContentAd, + ad, ConfirmationType::kViewed); + ad_events.push_back(ad_event_3); + + // Act + TotalMaxFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad); + + // Assert + EXPECT_FALSE(should_exclude); +} + TEST_F(BatAdsTotalMaxFrequencyCapTest, AllowAdIfDoesNotExceedCapForNoMatchingCreatives) { // Arrange diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap.cc index 9ad8c7b07785..f1ef3a05586d 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap.cc @@ -64,7 +64,7 @@ AdEventList TransferredFrequencyCap::FilterAdEvents( const auto iter = std::remove_if(filtered_ad_events.begin(), filtered_ad_events.end(), [&ad](const AdEventInfo& ad_event) { - return ad_event.type == AdType::kNewTabPageAd || + return ad_event.type != AdType::kAdNotification || ad_event.campaign_id != ad.campaign_id || ad_event.confirmation_type != ConfirmationType::kTransferred; }); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap_unittest.cc index 403a7846abf9..4e815d512021 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/exclusion_rules/transferred_frequency_cap_unittest.cc @@ -78,6 +78,41 @@ TEST_F(BatAdsTransferredFrequencyCapTest, EXPECT_FALSE(should_exclude); } +TEST_F(BatAdsTransferredFrequencyCapTest, + AdAllowedForAdWithDifferentCampaignIdWithin48HoursForMultipleTypes) { + // Arrange + CreativeAdInfo ad_1; + ad_1.creative_instance_id = kCreativeInstanceId; + ad_1.campaign_id = kCampaignIds.at(0); + + CreativeAdInfo ad_2; + ad_2.creative_instance_id = kCreativeInstanceId; + ad_2.campaign_id = kCampaignIds.at(1); + + AdEventList ad_events; + + const AdEventInfo ad_event_1 = GenerateAdEvent(AdType::kAdNotification, + ad_2, ConfirmationType::kTransferred); + ad_events.push_back(ad_event_1); + + const AdEventInfo ad_event_2 = GenerateAdEvent(AdType::kNewTabPageAd, + ad_2, ConfirmationType::kTransferred); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_3 = GenerateAdEvent(AdType::kPromotedContentAd, + ad_2, ConfirmationType::kTransferred); + ad_events.push_back(ad_event_3); + + task_environment_.FastForwardBy(base::TimeDelta::FromHours(47)); + + // Act + TransferredFrequencyCap frequency_cap(ad_events); + const bool should_exclude = frequency_cap.ShouldExclude(ad_1); + + // Assert + EXPECT_FALSE(should_exclude); +} + TEST_F(BatAdsTransferredFrequencyCapTest, AdNotAllowedForAdWithSameCampaignIdWithin48Hours) { // Arrange diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/catalog_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/catalog_frequency_cap_unittest.cc index 911963d8bf7a..68cb81014dd2 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/catalog_frequency_cap_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/catalog_frequency_cap_unittest.cc @@ -30,7 +30,7 @@ TEST_F(BatAdsCatalogFrequencyCapTest, // Arrange const URLEndpoints endpoints = { { - "/v5/catalog", { + "/v6/catalog", { { net::HTTP_OK, "/catalog.json" } @@ -55,7 +55,7 @@ TEST_F(BatAdsCatalogFrequencyCapTest, // Arrange const URLEndpoints endpoints = { { - "/v5/catalog", { + "/v6/catalog", { { net::HTTP_OK, "/catalog.json" } @@ -83,7 +83,7 @@ TEST_F(BatAdsCatalogFrequencyCapTest, // Arrange const URLEndpoints endpoints = { { - "/v5/catalog", { + "/v6/catalog", { { net::HTTP_OK, "/catalog.json" } diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.cc new file mode 100644 index 000000000000..13779c2f2808 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.cc @@ -0,0 +1,64 @@ +/* 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/permission_rules/promoted_content_ads_per_day_frequency_cap.h" + +#include + +#include "base/time/time.h" +#include "bat/ads/internal/frequency_capping/frequency_capping_util.h" + +namespace ads { + +PromotedContentAdsPerDayFrequencyCap::PromotedContentAdsPerDayFrequencyCap( + const AdEventList& ad_events) + : ad_events_(ad_events) { +} + +PromotedContentAdsPerDayFrequencyCap:: +~PromotedContentAdsPerDayFrequencyCap() = default; + +bool PromotedContentAdsPerDayFrequencyCap::ShouldAllow() { + const AdEventList filtered_ad_events = FilterAdEvents(ad_events_); + if (!DoesRespectCap(filtered_ad_events)) { + last_message_ = "You have exceeded the allowed new tab page ads per day"; + return false; + } + + return true; +} + +std::string PromotedContentAdsPerDayFrequencyCap::get_last_message() const { + return last_message_; +} + +bool PromotedContentAdsPerDayFrequencyCap::DoesRespectCap( + const AdEventList& ad_events) { + const std::deque history = + GetTimestampHistoryForAdEvents(ad_events); + + const uint64_t time_constraint = base::Time::kSecondsPerHour * + base::Time::kHoursPerDay; + + return DoesHistoryRespectCapForRollingTimeConstraint( + history, time_constraint, kPromotedContentAdsPerDayFrequencyCap); +} + +AdEventList PromotedContentAdsPerDayFrequencyCap::FilterAdEvents( + const AdEventList& ad_events) const { + AdEventList filtered_ad_events = ad_events; + + const auto iter = std::remove_if(filtered_ad_events.begin(), + filtered_ad_events.end(), [](const AdEventInfo& ad_event) { + return ad_event.type != AdType::kPromotedContentAd || + ad_event.confirmation_type != ConfirmationType::kViewed; + }); + + filtered_ad_events.erase(iter, filtered_ad_events.end()); + + return filtered_ad_events; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.h b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.h new file mode 100644 index 000000000000..5dc47e598e77 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.h @@ -0,0 +1,50 @@ +/* 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_PERMISSION_RULES_PROMOTED_CONTENT_ADS_PER_DAY_FREQUENCY_CAP_H_ // NOLINT +#define BAT_ADS_INTERNAL_FREQUENCY_CAPPING_PERMISSION_RULES_PROMOTED_CONTENT_ADS_PER_DAY_FREQUENCY_CAP_H_ // NOLINT + +#include + +#include + +#include "bat/ads/internal/ad_events/ad_event_info.h" +#include "bat/ads/internal/frequency_capping/permission_rules/permission_rule.h" + +namespace ads { + +const uint64_t kPromotedContentAdsPerDayFrequencyCap = 20; + +class PromotedContentAdsPerDayFrequencyCap : public PermissionRule { + public: + PromotedContentAdsPerDayFrequencyCap( + const AdEventList& ad_events); + + ~PromotedContentAdsPerDayFrequencyCap() override; + + PromotedContentAdsPerDayFrequencyCap( + const PromotedContentAdsPerDayFrequencyCap&) = delete; + PromotedContentAdsPerDayFrequencyCap& operator=( + const PromotedContentAdsPerDayFrequencyCap&) = delete; + + bool ShouldAllow() override; + + std::string get_last_message() const override; + + private: + AdEventList ad_events_; + + std::string last_message_; + + bool DoesRespectCap( + const AdEventList& ad_events); + + AdEventList FilterAdEvents( + const AdEventList& ad_events) const; +}; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_FREQUENCY_CAPPING_PERMISSION_RULES_PROMOTED_CONTENT_ADS_PER_DAY_FREQUENCY_CAP_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap_unittest.cc new file mode 100644 index 000000000000..72040ce60360 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap_unittest.cc @@ -0,0 +1,113 @@ +/* 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/permission_rules/promoted_content_ads_per_day_frequency_cap.h" + +#include "bat/ads/internal/frequency_capping/frequency_capping_unittest_util.h" +#include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_util.h" +#include "bat/ads/pref_names.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +namespace { +const char kCreativeInstanceId[] = "9aea9a47-c6a0-4718-a0fa-706338bb2156"; +} // namespace + +class BatAdsPromotedContentAdsPerDayFrequencyCapTest : public UnitTestBase { + protected: + BatAdsPromotedContentAdsPerDayFrequencyCapTest() = default; + + ~BatAdsPromotedContentAdsPerDayFrequencyCapTest() override = default; +}; + +TEST_F(BatAdsPromotedContentAdsPerDayFrequencyCapTest, + AllowAdIfThereIsNoAdsHistory) { + // Arrange + const AdEventList ad_events; + + // Act + PromotedContentAdsPerDayFrequencyCap frequency_cap(ad_events); + const bool is_allowed = frequency_cap.ShouldAllow(); + + // Assert + EXPECT_TRUE(is_allowed); +} + +TEST_F(BatAdsPromotedContentAdsPerDayFrequencyCapTest, + AllowAdIfDoesNotExceedCap) { + // Arrange + CreativeAdInfo ad; + ad.creative_instance_id = kCreativeInstanceId; + + const AdEventInfo ad_event = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + + const AdEventList ad_events(kPromotedContentAdsPerDayFrequencyCap - 1, + ad_event); + + // Act + PromotedContentAdsPerDayFrequencyCap frequency_cap(ad_events); + const bool is_allowed = frequency_cap.ShouldAllow(); + + // Assert + EXPECT_TRUE(is_allowed); +} + +TEST_F(BatAdsPromotedContentAdsPerDayFrequencyCapTest, + AllowAdIfDoesNotExceedCapAfter1Day) { + // Arrange + CreativeAdInfo ad; + ad.creative_instance_id = kCreativeInstanceId; + + const AdEventInfo ad_event = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + + const AdEventList ad_events(kPromotedContentAdsPerDayFrequencyCap, ad_event); + + FastForwardClockBy(base::TimeDelta::FromDays(1)); + + // Act + PromotedContentAdsPerDayFrequencyCap frequency_cap(ad_events); + const bool is_allowed = frequency_cap.ShouldAllow(); + + // Assert + EXPECT_TRUE(is_allowed); +} + +TEST_F(BatAdsPromotedContentAdsPerDayFrequencyCapTest, + DoNotAllowAdIfExceedsCapWithin1Day) { + // Arrange + CreativeAdInfo ad; + ad.creative_instance_id = kCreativeInstanceId; + + const AdEventInfo ad_event = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + + const AdEventList ad_events(kPromotedContentAdsPerDayFrequencyCap, ad_event); + + FastForwardClockBy(base::TimeDelta::FromHours(23)); + + // Act + PromotedContentAdsPerDayFrequencyCap frequency_cap(ad_events); + const bool is_allowed = frequency_cap.ShouldAllow(); + + // Assert + EXPECT_FALSE(is_allowed); +} + +TEST_F(BatAdsPromotedContentAdsPerDayFrequencyCapTest, + AdsPerDay) { + // Arrange + + // Act + + // Assert + EXPECT_EQ(20UL, kPromotedContentAdsPerDayFrequencyCap); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.cc new file mode 100644 index 000000000000..96c96f26c6d3 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.cc @@ -0,0 +1,64 @@ +/* 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/permission_rules/promoted_content_ads_per_hour_frequency_cap.h" + +#include + +#include "base/time/time.h" +#include "bat/ads/internal/frequency_capping/frequency_capping_util.h" + +namespace ads { + +PromotedContentAdsPerHourFrequencyCap::PromotedContentAdsPerHourFrequencyCap( + const AdEventList& ad_events) + : ad_events_(ad_events) { +} + +PromotedContentAdsPerHourFrequencyCap:: +~PromotedContentAdsPerHourFrequencyCap() = default; + +bool PromotedContentAdsPerHourFrequencyCap::ShouldAllow() { + const AdEventList filtered_ad_events = FilterAdEvents(ad_events_); + if (!DoesRespectCap(filtered_ad_events)) { + last_message_ = + "You have exceeded the allowed promoted content ads per hour"; + return false; + } + + return true; +} + +std::string PromotedContentAdsPerHourFrequencyCap::get_last_message() const { + return last_message_; +} + +bool PromotedContentAdsPerHourFrequencyCap::DoesRespectCap( + const AdEventList& ad_events) { + const std::deque history = + GetTimestampHistoryForAdEvents(ad_events); + + const uint64_t time_constraint = base::Time::kSecondsPerHour; + + return DoesHistoryRespectCapForRollingTimeConstraint( + history, time_constraint, kPromotedContentAdsPerHourFrequencyCap); +} + +AdEventList PromotedContentAdsPerHourFrequencyCap::FilterAdEvents( + const AdEventList& ad_events) const { + AdEventList filtered_ad_events = ad_events; + + const auto iter = std::remove_if(filtered_ad_events.begin(), + filtered_ad_events.end(), [](const AdEventInfo& ad_event) { + return ad_event.type != AdType::kPromotedContentAd || + ad_event.confirmation_type != ConfirmationType::kViewed; + }); + + filtered_ad_events.erase(iter, filtered_ad_events.end()); + + return filtered_ad_events; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.h b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.h new file mode 100644 index 000000000000..9db1fae793de --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.h @@ -0,0 +1,50 @@ +/* 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_PERMISSION_RULES_PROMOTED_CONTENT_ADS_PER_HOUR_FREQUENCY_CAP_H_ // NOLINT +#define BAT_ADS_INTERNAL_FREQUENCY_CAPPING_PERMISSION_RULES_PROMOTED_CONTENT_ADS_PER_HOUR_FREQUENCY_CAP_H_ // NOLINT + +#include + +#include + +#include "bat/ads/internal/ad_events/ad_event_info.h" +#include "bat/ads/internal/frequency_capping/permission_rules/permission_rule.h" + +namespace ads { + +const uint64_t kPromotedContentAdsPerHourFrequencyCap = 4; + +class PromotedContentAdsPerHourFrequencyCap : public PermissionRule { + public: + PromotedContentAdsPerHourFrequencyCap( + const AdEventList& ad_events); + + ~PromotedContentAdsPerHourFrequencyCap() override; + + PromotedContentAdsPerHourFrequencyCap( + const PromotedContentAdsPerHourFrequencyCap&) = delete; + PromotedContentAdsPerHourFrequencyCap& operator=( + const PromotedContentAdsPerHourFrequencyCap&) = delete; + + bool ShouldAllow() override; + + std::string get_last_message() const override; + + private: + AdEventList ad_events_; + + std::string last_message_; + + bool DoesRespectCap( + const AdEventList& ad_events); + + AdEventList FilterAdEvents( + const AdEventList& ad_events) const; +}; + +} // namespace ads + +#endif // BAT_ADS_INTERNAL_FREQUENCY_CAPPING_PERMISSION_RULES_PROMOTED_CONTENT_ADS_PER_HOUR_FREQUENCY_CAP_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap_unittest.cc new file mode 100644 index 000000000000..4c1578491160 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap_unittest.cc @@ -0,0 +1,113 @@ +/* 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/permission_rules/promoted_content_ads_per_hour_frequency_cap.h" + +#include "bat/ads/internal/frequency_capping/frequency_capping_unittest_util.h" +#include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_util.h" +#include "bat/ads/pref_names.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +namespace { +const char kCreativeInstanceId[] = "9aea9a47-c6a0-4718-a0fa-706338bb2156"; +} // namespace + +class BatAdsPromotedContentAdsPerHourFrequencyCapTest : public UnitTestBase { + protected: + BatAdsPromotedContentAdsPerHourFrequencyCapTest() = default; + + ~BatAdsPromotedContentAdsPerHourFrequencyCapTest() override = default; +}; + +TEST_F(BatAdsPromotedContentAdsPerHourFrequencyCapTest, + AllowAdIfThereIsNoAdsHistory) { + // Arrange + const AdEventList ad_events; + + // Act + PromotedContentAdsPerHourFrequencyCap frequency_cap(ad_events); + const bool is_allowed = frequency_cap.ShouldAllow(); + + // Assert + EXPECT_TRUE(is_allowed); +} + +TEST_F(BatAdsPromotedContentAdsPerHourFrequencyCapTest, + AllowAdIfDoesNotExceedCap) { + // Arrange + CreativeAdInfo ad; + ad.creative_instance_id = kCreativeInstanceId; + + const AdEventInfo ad_event = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + + const AdEventList ad_events(kPromotedContentAdsPerHourFrequencyCap - 1, + ad_event); + + // Act + PromotedContentAdsPerHourFrequencyCap frequency_cap(ad_events); + const bool is_allowed = frequency_cap.ShouldAllow(); + + // Assert + EXPECT_TRUE(is_allowed); +} + +TEST_F(BatAdsPromotedContentAdsPerHourFrequencyCapTest, + AllowAdIfDoesNotExceedCapAfter1Hour) { + // Arrange + CreativeAdInfo ad; + ad.creative_instance_id = kCreativeInstanceId; + + const AdEventInfo ad_event = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + + const AdEventList ad_events(kPromotedContentAdsPerHourFrequencyCap, ad_event); + + FastForwardClockBy(base::TimeDelta::FromHours(1)); + + // Act + PromotedContentAdsPerHourFrequencyCap frequency_cap(ad_events); + const bool is_allowed = frequency_cap.ShouldAllow(); + + // Assert + EXPECT_TRUE(is_allowed); +} + +TEST_F(BatAdsPromotedContentAdsPerHourFrequencyCapTest, + DoNotAllowAdIfExceedsCapWithin1Hour) { + // Arrange + CreativeAdInfo ad; + ad.creative_instance_id = kCreativeInstanceId; + + const AdEventInfo ad_event = GenerateAdEvent(AdType::kPromotedContentAd, ad, + ConfirmationType::kViewed); + + const AdEventList ad_events(kPromotedContentAdsPerHourFrequencyCap, ad_event); + + FastForwardClockBy(base::TimeDelta::FromMinutes(59)); + + // Act + PromotedContentAdsPerHourFrequencyCap frequency_cap(ad_events); + const bool is_allowed = frequency_cap.ShouldAllow(); + + // Assert + EXPECT_FALSE(is_allowed); +} + +TEST_F(BatAdsPromotedContentAdsPerHourFrequencyCapTest, + AdsPerHour) { + // Arrange + + // Act + + // Assert + EXPECT_EQ(4UL, kPromotedContentAdsPerHourFrequencyCap); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.cc b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.cc new file mode 100644 index 000000000000..d0899cda4618 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.cc @@ -0,0 +1,53 @@ +/* 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/promoted_content_ads/promoted_content_ads_frequency_capping.h" + +#include "bat/ads/ad_info.h" +#include "bat/ads/internal/frequency_capping/exclusion_rules/exclusion_rule_util.h" +#include "bat/ads/internal/frequency_capping/exclusion_rules/promoted_content_ad_uuid_frequency_cap.h" +#include "bat/ads/internal/frequency_capping/permission_rules/permission_rule_util.h" +#include "bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_day_frequency_cap.h" +#include "bat/ads/internal/frequency_capping/permission_rules/promoted_content_ads_per_hour_frequency_cap.h" +#include "bat/ads/internal/frequency_capping/permission_rules/unblinded_tokens_frequency_cap.h" +#include "bat/ads/internal/logging.h" + +namespace ads { +namespace promoted_content_ads { + +FrequencyCapping::FrequencyCapping( + const AdEventList& ad_events) + : ad_events_(ad_events) { +} + +FrequencyCapping::~FrequencyCapping() = default; + +bool FrequencyCapping::IsAdAllowed() { + UnblindedTokensFrequencyCap unblinded_tokens_frequency_cap; + if (!ShouldAllow(&unblinded_tokens_frequency_cap)) { + return false; + } + + PromotedContentAdsPerDayFrequencyCap ads_per_day_frequency_cap(ad_events_); + if (!ShouldAllow(&ads_per_day_frequency_cap)) { + return false; + } + + PromotedContentAdsPerHourFrequencyCap ads_per_hour_frequency_cap(ad_events_); + if (!ShouldAllow(&ads_per_hour_frequency_cap)) { + return false; + } + + return true; +} + +bool FrequencyCapping::ShouldExcludeAd( + const AdInfo& ad) { + PromotedContentAdUuidFrequencyCap frequency_cap(ad_events_); + return ShouldExclude(ad, &frequency_cap); +} + +} // namespace promoted_content_ads +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.h b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.h new file mode 100644 index 000000000000..71caef022e64 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/promoted_content_ads/promoted_content_ads_frequency_capping.h @@ -0,0 +1,41 @@ +/* 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_FREQUENCY_CAPPING_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_ADS_FREQUENCY_CAPPING_H_ // NOLINT +#define BAT_ADS_INTERNAL_FREQUENCY_CAPPING_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_ADS_FREQUENCY_CAPPING_H_ // NOLINT + +#include "bat/ads/internal/ad_events/ad_event_info.h" + +namespace ads { + +struct AdInfo; + +namespace promoted_content_ads { + +class FrequencyCapping { + public: + FrequencyCapping( + const AdEventList& ad_events); + + ~FrequencyCapping(); + + FrequencyCapping( + const FrequencyCapping&) = delete; + FrequencyCapping& operator=( + const FrequencyCapping&) = delete; + + bool IsAdAllowed(); + + bool ShouldExcludeAd( + const AdInfo& ad); + + private: + AdEventList ad_events_; +}; + +} // namespace promoted_content_ads +} // namespace ads + +#endif // BAT_ADS_INTERNAL_FREQUENCY_CAPPING_PROMOTED_CONTENT_ADS_PROMOTED_CONTENT_ADS_FREQUENCY_CAPPING_H_ // NOLINT diff --git a/vendor/bat-native-ads/src/bat/ads/promoted_content_ad_info.cc b/vendor/bat-native-ads/src/bat/ads/promoted_content_ad_info.cc new file mode 100644 index 000000000000..edb69b9380b2 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/promoted_content_ad_info.cc @@ -0,0 +1,126 @@ +/* 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/promoted_content_ad_info.h" + +#include "bat/ads/internal/logging.h" +#include "bat/ads/internal/json_helper.h" + +namespace ads { + +struct ConfirmationType; + +PromotedContentAdInfo::PromotedContentAdInfo() = default; + +PromotedContentAdInfo::PromotedContentAdInfo( + const PromotedContentAdInfo& info) = default; + +PromotedContentAdInfo::~PromotedContentAdInfo() = default; + +bool PromotedContentAdInfo::IsValid() const { + if (!AdInfo::IsValid()) { + return false; + } + + if (title.empty() || + description.empty()) { + return false; + } + + return true; +} + +std::string PromotedContentAdInfo::ToJson() const { + std::string json; + SaveToJson(*this, &json); + return json; +} + +Result PromotedContentAdInfo::FromJson( + const std::string& json) { + rapidjson::Document document; + document.Parse(json.c_str()); + + if (document.HasParseError()) { + BLOG(1, helper::JSON::GetLastError(&document)); + return FAILED; + } + + if (document.HasMember("type")) { + type = AdType(document["type"].GetString()); + } + + if (document.HasMember("uuid")) { + uuid = document["uuid"].GetString(); + } + + if (document.HasMember("creative_instance_id")) { + creative_instance_id = document["creative_instance_id"].GetString(); + } + + if (document.HasMember("creative_set_id")) { + creative_set_id = document["creative_set_id"].GetString(); + } + + if (document.HasMember("campaign_id")) { + campaign_id = document["campaign_id"].GetString(); + } + + if (document.HasMember("segment")) { + segment = document["segment"].GetString(); + } + + if (document.HasMember("title")) { + title = document["title"].GetString(); + } + + if (document.HasMember("description")) { + description = document["description"].GetString(); + } + + if (document.HasMember("target_url")) { + target_url = document["target_url"].GetString(); + } + + return SUCCESS; +} + +void SaveToJson( + JsonWriter* writer, + const PromotedContentAdInfo& info) { + writer->StartObject(); + + writer->String("type"); + const std::string type = std::string(info.type); + writer->String(type.c_str()); + + writer->String("uuid"); + writer->String(info.uuid.c_str()); + + writer->String("creative_instance_id"); + writer->String(info.creative_instance_id.c_str()); + + writer->String("creative_set_id"); + writer->String(info.creative_set_id.c_str()); + + writer->String("campaign_id"); + writer->String(info.campaign_id.c_str()); + + writer->String("segment"); + writer->String(info.segment.c_str()); + + writer->String("title"); + writer->String(info.title.c_str()); + + writer->String("description"); + writer->String(info.description.c_str()); + + writer->String("target_url"); + writer->String(info.target_url.c_str()); + + writer->EndObject(); +} + +} // namespace ads diff --git a/vendor/brave-ios/Ads/BATBraveAds.h b/vendor/brave-ios/Ads/BATBraveAds.h index c59ef4181107..23a075daeb00 100644 --- a/vendor/brave-ios/Ads/BATBraveAds.h +++ b/vendor/brave-ios/Ads/BATBraveAds.h @@ -14,10 +14,15 @@ typedef NS_ENUM(NSInteger, BATAdNotificationEventType) { } NS_SWIFT_NAME(AdNotificationEventType); typedef NS_ENUM(NSInteger, BATNewTabPageAdEventType) { - BATNewTabPageAdEventTypeViewed, // = ads::AdNotificationEventType::kViewed - BATNewTabPageAdEventTypeClicked // = ads::AdNotificationEventType::kClicked + BATNewTabPageAdEventTypeViewed, // = ads::NewTabPageAdEventType::kViewed + BATNewTabPageAdEventTypeClicked // = ads::NewTabPageAdEventType::kClicked } NS_SWIFT_NAME(NewTabPageAdEventType); +typedef NS_ENUM(NSInteger, BATPromotedContentAdEventType) { + BATPromotedContentAdEventTypeViewed, // = ads::PromotedContentAdEventType::kViewed + BATPromotedContentAdEventTypeClicked // = ads::PromotedContentAdEventType::kClicked +} NS_SWIFT_NAME(PromotedContentAdEventType); + NS_ASSUME_NONNULL_BEGIN @class BATAdNotification, BATBraveAds, BATBraveLedger; @@ -141,6 +146,11 @@ NS_SWIFT_NAME(BraveAds) creativeInstanceId:(NSString *)creativeInstanceId eventType:(BATNewTabPageAdEventType)eventType; +/// Report that a promoted content ad event type was triggered for a given id +- (void)reportPromotedContentAdEvent:(NSString *)uuid + creativeInstanceId:(NSString *)creativeInstanceId + eventType:(BATPromotedContentAdEventType)eventType; + /// Reconcile ad rewards with server - (void)reconcileAdRewards; diff --git a/vendor/brave-ios/Ads/BATBraveAds.mm b/vendor/brave-ios/Ads/BATBraveAds.mm index fb5ba09694ac..9478d04df7f2 100644 --- a/vendor/brave-ios/Ads/BATBraveAds.mm +++ b/vendor/brave-ios/Ads/BATBraveAds.mm @@ -543,6 +543,14 @@ - (void)reportNewTabPageAdEvent:(NSString *)wallpaperId creativeInstanceId:(NSSt static_cast(eventType)); } +- (void)reportPromotedContentAdEvent:(NSString *)uuid creativeInstanceId:(NSString *)creativeInstanceId eventType:(BATPromotedContentAdEventType)eventType +{ + if (![self isAdsServiceRunning]) { return; } + ads->OnPromotedContentAdEvent(uuid.UTF8String, + creativeInstanceId.UTF8String, + static_cast(eventType)); +} + - (void)reconcileAdRewards { if (![self isAdsServiceRunning]) { return; }