Skip to content

Commit cd4edd3

Browse files
authored
Merge pull request #4459 from /issues/7888
Round-robin Brave Ads campaign advertisers to reduce the frequency of showing the same ad
2 parents 7c26b4a + aa57999 commit cd4edd3

File tree

14 files changed

+164
-12
lines changed

14 files changed

+164
-12
lines changed

components/brave_ads/browser/bundle_state_database.cc

+32-10
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ namespace brave_ads {
2222

2323
namespace {
2424

25-
const int kCurrentVersionNumber = 3;
26-
const int kCompatibleVersionNumber = 3;
25+
const int kCurrentVersionNumber = 4;
26+
const int kCompatibleVersionNumber = 4;
2727

2828
} // namespace
2929

@@ -171,6 +171,7 @@ bool BundleStateDatabase::CreateAdInfoTable() {
171171
"region VARCHAR,"
172172
"campaign_id LONGVARCHAR,"
173173
"daily_cap INTEGER DEFAULT 0 NOT NULL,"
174+
"advertiser_id LONGVARCHAR,"
174175
"per_day INTEGER DEFAULT 0 NOT NULL,"
175176
"total_max INTEGER DEFAULT 0 NOT NULL,"
176177
"PRIMARY KEY(region, uuid))");
@@ -330,8 +331,9 @@ bool BundleStateDatabase::InsertOrUpdateAdInfo(const ads::AdInfo& info) {
330331
"INSERT OR REPLACE INTO ad_info "
331332
"(creative_set_id, advertiser, notification_text, "
332333
"notification_url, start_timestamp, end_timestamp, uuid, "
333-
"campaign_id, daily_cap, per_day, total_max, region) "
334-
"VALUES (?, ?, ?, ?, datetime(?), datetime(?), ?, ?, ?, ?, ?, ?)"));
334+
"campaign_id, daily_cap, advertiser_id, per_day, total_max, "
335+
"region) VALUES (?, ?, ?, ?, datetime(?), datetime(?), ?, ?, ?, "
336+
"?, ?, ?, ?)"));
335337

336338
ad_info_statement.BindString(0, info.creative_set_id);
337339
ad_info_statement.BindString(1, info.advertiser);
@@ -342,9 +344,10 @@ bool BundleStateDatabase::InsertOrUpdateAdInfo(const ads::AdInfo& info) {
342344
ad_info_statement.BindString(6, info.uuid);
343345
ad_info_statement.BindString(7, info.campaign_id);
344346
ad_info_statement.BindInt(8, info.daily_cap);
345-
ad_info_statement.BindInt(9, info.per_day);
346-
ad_info_statement.BindInt(10, info.total_max);
347-
ad_info_statement.BindString(11, *it);
347+
ad_info_statement.BindString(9, info.advertiser_id);
348+
ad_info_statement.BindInt(10, info.per_day);
349+
ad_info_statement.BindInt(11, info.total_max);
350+
ad_info_statement.BindString(12, *it);
348351
if (!ad_info_statement.Run()) {
349352
return false;
350353
}
@@ -418,7 +421,7 @@ bool BundleStateDatabase::GetAdsForCategory(
418421
"ai.notification_text, ai.notification_url, "
419422
"ai.start_timestamp, ai.end_timestamp, "
420423
"ai.uuid, ai.region, ai.campaign_id, ai.daily_cap, "
421-
"ai.per_day, ai.total_max FROM ad_info AS ai "
424+
"ai.advertiser_id, ai.per_day, ai.total_max FROM ad_info AS ai "
422425
"INNER JOIN ad_info_category AS aic "
423426
"ON aic.ad_info_uuid = ai.uuid "
424427
"WHERE aic.category_name = ? and "
@@ -440,8 +443,9 @@ bool BundleStateDatabase::GetAdsForCategory(
440443
info.uuid = info_sql.ColumnString(6);
441444
info.campaign_id = info_sql.ColumnString(8);
442445
info.daily_cap = info_sql.ColumnInt(9);
443-
info.per_day = info_sql.ColumnInt(10);
444-
info.total_max = info_sql.ColumnInt(11);
446+
info.advertiser_id = info_sql.ColumnString(10);
447+
info.per_day = info_sql.ColumnInt(11);
448+
info.total_max = info_sql.ColumnInt(12);
445449
ads->emplace_back(info);
446450
}
447451

@@ -558,6 +562,15 @@ bool BundleStateDatabase::Migrate() {
558562
break;
559563
}
560564

565+
case 3: {
566+
if (!MigrateV3toV4()) {
567+
LOG(ERROR) << "DB: Error migrating database from v3 to v4";
568+
return false;
569+
}
570+
571+
break;
572+
}
573+
561574
default: {
562575
NOTREACHED();
563576
return false;
@@ -620,4 +633,13 @@ bool BundleStateDatabase::MigrateV2toV3() {
620633
return GetDB().Execute(sql.c_str());
621634
}
622635

636+
bool BundleStateDatabase::MigrateV3toV4() {
637+
std::string sql = "ALTER TABLE ad_info ADD advertiser_id LONGVARCHAR;";
638+
if (!GetDB().Execute(sql.c_str())) {
639+
return false;
640+
}
641+
642+
return false;
643+
}
644+
623645
} // namespace brave_ads

components/brave_ads/browser/bundle_state_database.h

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class BundleStateDatabase {
8787
bool Migrate();
8888
bool MigrateV1toV2();
8989
bool MigrateV2toV3();
90+
bool MigrateV3toV4();
9091

9192
sql::Database db_;
9293
sql::MetaTable meta_table_;

vendor/bat-native-ads/include/bat/ads/ad_info.h

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct ADS_EXPORT AdInfo {
2929
std::string start_timestamp;
3030
std::string end_timestamp;
3131
unsigned int daily_cap;
32+
std::string advertiser_id;
3233
unsigned int per_day;
3334
unsigned int total_max;
3435
std::vector<std::string> regions;

vendor/bat-native-ads/resources/bundle-schema.json

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
"dailyCap": {
3333
"type": "number"
3434
},
35+
"advertiserId": {
36+
"type": "string"
37+
},
3538
"perDay": {
3639
"type": "number"
3740
},

vendor/bat-native-ads/src/bat/ads/ad_info.cc

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ AdInfo::AdInfo(const AdInfo& info) :
2020
start_timestamp(info.start_timestamp),
2121
end_timestamp(info.end_timestamp),
2222
daily_cap(info.daily_cap),
23+
advertiser_id(info.advertiser_id),
2324
per_day(info.per_day),
2425
total_max(info.total_max),
2526
regions(info.regions),
@@ -71,6 +72,10 @@ Result AdInfo::FromJson(
7172
daily_cap = document["daily_cap"].GetUint();
7273
}
7374

75+
if (document.HasMember("advertiser_id")) {
76+
advertiser_id = document["advertiser_id"].GetString();
77+
}
78+
7479
if (document.HasMember("per_day")) {
7580
per_day = document["per_day"].GetUint();
7681
}
@@ -128,6 +133,9 @@ void SaveToJson(JsonWriter* writer, const AdInfo& info) {
128133
writer->String("daily_cap");
129134
writer->Uint(info.daily_cap);
130135

136+
writer->String("advertiser_id");
137+
writer->String(info.advertiser_id.c_str());
138+
131139
writer->String("per_day");
132140
writer->Uint(info.per_day);
133141

vendor/bat-native-ads/src/bat/ads/bundle_state.cc

+7
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ Result BundleState::FromJson(
7575
ad_info.daily_cap = info["dailyCap"].GetUint();
7676
}
7777

78+
if (info.HasMember("advertiserId")) {
79+
ad_info.advertiser_id = info["advertiserId"].GetString();
80+
}
81+
7882
if (info.HasMember("perDay")) {
7983
ad_info.per_day = info["perDay"].GetUint();
8084
}
@@ -171,6 +175,9 @@ void SaveToJson(JsonWriter* writer, const BundleState& state) {
171175
writer->String("dailyCap");
172176
writer->Uint(ad.daily_cap);
173177

178+
writer->String("advertiserId");
179+
writer->String(ad.advertiser_id.c_str());
180+
174181
writer->String("perDay");
175182
writer->Uint(ad.per_day);
176183

vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc

+56-2
Original file line numberDiff line numberDiff line change
@@ -1317,13 +1317,47 @@ std::vector<AdInfo> AdsImpl::GetUnseenAdsAndRoundRobinIfNeeded(
13171317
return ads;
13181318
}
13191319

1320-
auto unseen_ads = GetUnseenAds(ads);
1320+
std::vector<AdInfo> ads_for_unseen_advertisers =
1321+
GetAdsForUnseenAdvertisers(ads);
1322+
if (ads_for_unseen_advertisers.empty()) {
1323+
BLOG(INFO) << "All advertisers have been shown, so round robin";
1324+
1325+
const bool should_not_show_last_advertiser =
1326+
client_->GetAdvertisersUUIDSeen().size() > 1 ? true : false;
1327+
1328+
client_->ResetAdvertisersUUIDSeen(ads);
1329+
1330+
ads_for_unseen_advertisers = GetAdsForUnseenAdvertisers(ads);
1331+
1332+
if (should_not_show_last_advertiser) {
1333+
const auto it = std::remove_if(ads_for_unseen_advertisers.begin(),
1334+
ads_for_unseen_advertisers.end(), [&](AdInfo& ad) {
1335+
return ad.advertiser_id == last_shown_ad_info_.advertiser_id;
1336+
});
1337+
1338+
ads_for_unseen_advertisers.erase(it, ads_for_unseen_advertisers.end());
1339+
}
1340+
}
1341+
1342+
std::vector<AdInfo> unseen_ads = GetUnseenAds(ads_for_unseen_advertisers);
13211343
if (unseen_ads.empty()) {
13221344
BLOG(INFO) << "All ads have been shown, so round robin";
13231345

1346+
const bool should_not_show_last_ad =
1347+
client_->GetAdsUUIDSeen().size() > 1 ? true : false;
1348+
13241349
client_->ResetAdsUUIDSeen(ads);
13251350

13261351
unseen_ads = GetUnseenAds(ads);
1352+
1353+
if (should_not_show_last_ad) {
1354+
const auto it = std::remove_if(ads_for_unseen_advertisers.begin(),
1355+
ads_for_unseen_advertisers.end(), [&](AdInfo& ad) {
1356+
return ad.uuid == last_shown_ad_info_.uuid;
1357+
});
1358+
1359+
ads_for_unseen_advertisers.erase(it, ads_for_unseen_advertisers.end());
1360+
}
13271361
}
13281362

13291363
return unseen_ads;
@@ -1333,10 +1367,27 @@ std::vector<AdInfo> AdsImpl::GetUnseenAds(
13331367
const std::vector<AdInfo>& ads) const {
13341368
auto unseen_ads = ads;
13351369
const auto seen_ads = client_->GetAdsUUIDSeen();
1370+
const auto seen_advertisers = client_->GetAdvertisersUUIDSeen();
13361371

13371372
const auto it = std::remove_if(unseen_ads.begin(), unseen_ads.end(),
13381373
[&](AdInfo& ad) {
1339-
return seen_ads.find(ad.uuid) != seen_ads.end();
1374+
return seen_ads.find(ad.uuid) != seen_ads.end() &&
1375+
seen_ads.find(ad.advertiser_id) != seen_advertisers.end();
1376+
});
1377+
1378+
unseen_ads.erase(it, unseen_ads.end());
1379+
1380+
return unseen_ads;
1381+
}
1382+
1383+
std::vector<AdInfo> AdsImpl::GetAdsForUnseenAdvertisers(
1384+
const std::vector<AdInfo>& ads) const {
1385+
auto unseen_ads = ads;
1386+
const auto seen_ads = client_->GetAdvertisersUUIDSeen();
1387+
1388+
const auto it = std::remove_if(unseen_ads.begin(), unseen_ads.end(),
1389+
[&](AdInfo& ad) {
1390+
return seen_ads.find(ad.advertiser_id) != seen_ads.end();
13401391
});
13411392

13421393
unseen_ads.erase(it, unseen_ads.end());
@@ -1381,6 +1432,9 @@ bool AdsImpl::ShowAd(
13811432
now_in_seconds);
13821433

13831434
client_->UpdateAdsUUIDSeen(ad.uuid, 1);
1435+
client_->UpdateAdvertisersUUIDSeen(ad.advertiser_id, 1);
1436+
1437+
last_shown_ad_info_ = ad;
13841438

13851439
auto notification_info = std::make_unique<NotificationInfo>();
13861440
notification_info->id = base::GenerateGUID();

vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h

+3
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,13 @@ class AdsImpl : public Ads {
232232
const std::vector<AdInfo>& ads) const;
233233
std::vector<AdInfo> GetUnseenAds(
234234
const std::vector<AdInfo>& ads) const;
235+
std::vector<AdInfo> GetAdsForUnseenAdvertisers(
236+
const std::vector<AdInfo>& ads) const;
235237

236238
bool IsAdValid(
237239
const AdInfo& ad_info);
238240
NotificationInfo last_shown_notification_info_;
241+
AdInfo last_shown_ad_info_;
239242
bool ShowAd(
240243
const AdInfo& ad_info);
241244
bool IsAllowedToServeAds();

vendor/bat-native-ads/src/bat/ads/internal/bundle.cc

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ std::unique_ptr<BundleState> Bundle::GenerateFromCatalog(
129129
ad_info.start_timestamp = campaign.start_at;
130130
ad_info.end_timestamp = campaign.end_at;
131131
ad_info.daily_cap = campaign.daily_cap;
132+
ad_info.advertiser_id = campaign.advertiser_id;
132133
ad_info.per_day = creative_set.per_day;
133134
ad_info.total_max = creative_set.total_max;
134135
ad_info.regions = regions;

vendor/bat-native-ads/src/bat/ads/internal/catalog_state.cc

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Result CatalogState::FromJson(
6666
campaign_info.start_at = campaign["startAt"].GetString();
6767
campaign_info.end_at = campaign["endAt"].GetString();
6868
campaign_info.daily_cap = campaign["dailyCap"].GetUint();
69+
campaign_info.advertiser_id = campaign["advertiserId"].GetString();
6970

7071
// Geo targets
7172
for (const auto& geo_target : campaign["geoTargets"].GetArray()) {

vendor/bat-native-ads/src/bat/ads/internal/client.cc

+27
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,33 @@ void Client::ResetAdsUUIDSeen(
364364
SaveState();
365365
}
366366

367+
void Client::UpdateAdvertisersUUIDSeen(
368+
const std::string& uuid,
369+
const uint64_t value) {
370+
client_state_->advertisers_uuid_seen.insert({uuid, value});
371+
372+
SaveState();
373+
}
374+
375+
const std::map<std::string, uint64_t> Client::GetAdvertisersUUIDSeen() {
376+
return client_state_->advertisers_uuid_seen;
377+
}
378+
379+
void Client::ResetAdvertisersUUIDSeen(
380+
const std::vector<AdInfo>& ads) {
381+
BLOG(INFO) << "Resetting seen advertisers";
382+
383+
for (const auto& ad : ads) {
384+
auto advertiser_uuid_seen =
385+
client_state_->advertisers_uuid_seen.find(ad.advertiser_id);
386+
if (advertiser_uuid_seen != client_state_->advertisers_uuid_seen.end()) {
387+
client_state_->advertisers_uuid_seen.erase(advertiser_uuid_seen);
388+
}
389+
}
390+
391+
SaveState();
392+
}
393+
367394
void Client::SetNextCheckServeAdTimestampInSeconds(
368395
const uint64_t timestamp_in_seconds) {
369396
client_state_->next_check_serve_ad_timestamp_in_seconds

vendor/bat-native-ads/src/bat/ads/internal/client.h

+6
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ class Client {
5555
void UpdateAdsUUIDSeen(const std::string& uuid, uint64_t value);
5656
const std::map<std::string, uint64_t> GetAdsUUIDSeen();
5757
void ResetAdsUUIDSeen(const std::vector<AdInfo>& ads);
58+
void UpdateAdvertisersUUIDSeen(
59+
const std::string& uuid,
60+
const uint64_t value);
61+
const std::map<std::string, uint64_t> GetAdvertisersUUIDSeen();
62+
void ResetAdvertisersUUIDSeen(
63+
const std::vector<AdInfo>& ads);
5864
void SetNextCheckServeAdTimestampInSeconds(
5965
const uint64_t timestamp_in_seconds);
6066
uint64_t GetNextCheckServeAdTimestampInSeconds();

vendor/bat-native-ads/src/bat/ads/internal/client_state.cc

+17
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ ClientState::ClientState(const ClientState& state)
3131
ads_shown_history(state.ads_shown_history),
3232
ad_uuid(state.ad_uuid),
3333
ads_uuid_seen(state.ads_uuid_seen),
34+
advertisers_uuid_seen(state.advertisers_uuid_seen),
3435
next_check_serve_ad_timestamp_in_seconds(
3536
state.next_check_serve_ad_timestamp_in_seconds),
3637
available(state.available),
@@ -112,6 +113,14 @@ Result ClientState::FromJson(
112113
}
113114
}
114115

116+
if (client.HasMember("advertisersUUIDSeen")) {
117+
for (const auto& advertiser_uuid_seen :
118+
client["advertisersUUIDSeen"].GetObject()) {
119+
advertisers_uuid_seen.insert({advertiser_uuid_seen.name.GetString(),
120+
advertiser_uuid_seen.value.GetInt64()});
121+
}
122+
}
123+
115124
if (client.HasMember("nextCheckServeAd")) {
116125
next_check_serve_ad_timestamp_in_seconds =
117126
client["nextCheckServeAd"].GetUint64();
@@ -265,6 +274,14 @@ void SaveToJson(JsonWriter* writer, const ClientState& state) {
265274
}
266275
writer->EndObject();
267276

277+
writer->String("advertisersUUIDSeen");
278+
writer->StartObject();
279+
for (const auto& advertiser_uuid_seen : state.advertisers_uuid_seen) {
280+
writer->String(advertiser_uuid_seen.first.c_str());
281+
writer->Uint64(advertiser_uuid_seen.second);
282+
}
283+
writer->EndObject();
284+
268285
writer->String("nextCheckServeAd");
269286
writer->Uint64(state.next_check_serve_ad_timestamp_in_seconds);
270287

vendor/bat-native-ads/src/bat/ads/internal/client_state.h

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct ClientState {
3333
std::deque<AdHistory> ads_shown_history;
3434
std::string ad_uuid;
3535
std::map<std::string, uint64_t> ads_uuid_seen;
36+
std::map<std::string, uint64_t> advertisers_uuid_seen;
3637
uint64_t next_check_serve_ad_timestamp_in_seconds;
3738
bool available;
3839
uint64_t last_search_time;

0 commit comments

Comments
 (0)