diff --git a/components/brave_rewards/browser/BUILD.gn b/components/brave_rewards/browser/BUILD.gn index 2de6ae2c23e2..90834ed2afe2 100644 --- a/components/brave_rewards/browser/BUILD.gn +++ b/components/brave_rewards/browser/BUILD.gn @@ -74,6 +74,10 @@ source_set("browser") { if (brave_rewards_enabled) { sources += [ + "database/database_contribution_queue.cc", + "database/database_contribution_queue.h", + "database/database_contribution_queue_publishers.cc", + "database/database_contribution_queue_publishers.h", "database/database_server_publisher_amounts.cc", "database/database_server_publisher_amounts.h", "database/database_server_publisher_banner.cc", diff --git a/components/brave_rewards/browser/database/database_contribution_queue.cc b/components/brave_rewards/browser/database/database_contribution_queue.cc new file mode 100644 index 000000000000..3448b8d014a4 --- /dev/null +++ b/components/brave_rewards/browser/database/database_contribution_queue.cc @@ -0,0 +1,173 @@ +/* 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/. */ + +#include "brave/components/brave_rewards/browser/database/database_contribution_queue.h" + +#include +#include + +#include "base/bind.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "sql/statement.h" +#include "sql/transaction.h" + +namespace brave_rewards { + +DatabaseContributionQueue::DatabaseContributionQueue(int current_db_version) : + DatabaseTable(current_db_version), + publishers_(std::make_unique + (current_db_version)) { +} + +DatabaseContributionQueue::~DatabaseContributionQueue() { +} + +std::string DatabaseContributionQueue::GetIdColumnName() { + return base::StringPrintf("%s_id", table_name_); +} + +bool DatabaseContributionQueue::Init(sql::Database* db) { + if (GetCurrentDBVersion() < minimum_version_) { + return true; + } + + sql::Transaction transaction(db); + if (!transaction.Begin()) { + return false; + } + + bool success = CreateTable(db); + if (!success) { + return false; + } + + success = publishers_->Init(db); + if (!success) { + return false; + } + + return transaction.Commit(); +} + +bool DatabaseContributionQueue::CreateTable(sql::Database* db) { + if (db->DoesTableExist(table_name_)) { + return true; + } + + const std::string query = base::StringPrintf( + "CREATE TABLE %s (" + "%s INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + "type INTEGER NOT NULL," + "amount DOUBLE NOT NULL," + "partial INTEGER NOT NULL DEFAULT 0," + "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL" + ")", + table_name_, + GetIdColumnName().c_str()); + + return db->Execute(query.c_str()); +} + +bool DatabaseContributionQueue::CreateIndex(sql::Database* db) { + return true; +} + +bool DatabaseContributionQueue::InsertOrUpdate( + sql::Database* db, + ledger::ContributionQueuePtr info) { + if (!info) { + return false; + } + + sql::Transaction transaction(db); + if (!transaction.Begin()) { + return false; + } + const std::string query = base::StringPrintf( + "INSERT OR REPLACE INTO %s (%s, type, amount, partial) " + "VALUES (?, ?, ?, ?)", + table_name_, + GetIdColumnName().c_str()); + + sql::Statement statement( + db->GetCachedStatement(SQL_FROM_HERE, query.c_str())); + + if (info->id != 0) { + statement.BindInt64(0, info->id); + } else { + statement.BindNull(0); + } + + statement.BindInt(1, static_cast(info->type)); + statement.BindDouble(2, info->amount); + statement.BindBool(3, info->partial); + + if (!statement.Run()) { + return false; + } + + if (info->id == 0) { + info->id = db->GetLastInsertRowId(); + } + + if (!publishers_->InsertOrUpdate(db, info->Clone())) { + transaction.Rollback(); + return false; + } + + return transaction.Commit(); +} + +ledger::ContributionQueuePtr DatabaseContributionQueue::GetFirstRecord( + sql::Database* db) { + const std::string query = base::StringPrintf( + "SELECT %s, type, amount, partial FROM %s ORDER BY %s ASC LIMIT 1", + GetIdColumnName().c_str(), + table_name_, + GetIdColumnName().c_str()); + + sql::Statement statment(db->GetUniqueStatement(query.c_str())); + + if (!statment.Step()) { + return nullptr; + } + + auto info = ledger::ContributionQueue::New(); + info->id = statment.ColumnInt64(0); + info->type = static_cast(statment.ColumnInt(1)); + info->amount = statment.ColumnDouble(2); + info->partial = static_cast(statment.ColumnInt(3)); + info->publishers = publishers_->GetRecords(db, info->id); + + return info; +} + +bool DatabaseContributionQueue::DeleteRecord( + sql::Database* db, + const uint64_t id) { + if (!db->Execute("PRAGMA foreign_keys=1;")) { + LOG(ERROR) << "Error: deleting record for contribution queue with id" << id; + return false; + } + + const std::string query = base::StringPrintf( + "DELETE FROM %s WHERE %s = ?", + table_name_, + GetIdColumnName().c_str()); + + sql::Statement statement(db->GetUniqueStatement(query.c_str())); + statement.BindInt64(0, id); + + bool success = statement.Run(); + + if (!db->Execute("PRAGMA foreign_keys=0;")) { + return false; + } + + return success; +} + +} // namespace brave_rewards diff --git a/components/brave_rewards/browser/database/database_contribution_queue.h b/components/brave_rewards/browser/database/database_contribution_queue.h new file mode 100644 index 000000000000..06f87636005e --- /dev/null +++ b/components/brave_rewards/browser/database/database_contribution_queue.h @@ -0,0 +1,45 @@ +/* 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 BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_DATABASE_DATABASE_CONTRIBUTION_QUEUE_H_ +#define BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_DATABASE_DATABASE_CONTRIBUTION_QUEUE_H_ + +#include +#include + +#include "bat/ledger/mojom_structs.h" +#include "brave/components/brave_rewards/browser/database/database_contribution_queue_publishers.h" +#include "brave/components/brave_rewards/browser/database/database_table.h" + +namespace brave_rewards { + +class DatabaseContributionQueue: public DatabaseTable { + public: + explicit DatabaseContributionQueue(int current_db_version); + ~DatabaseContributionQueue() override; + + bool Init(sql::Database* db) override; + + bool CreateTable(sql::Database* db) override; + + bool CreateIndex(sql::Database* db) override; + + bool InsertOrUpdate(sql::Database* db, ledger::ContributionQueuePtr info); + + ledger::ContributionQueuePtr GetFirstRecord(sql::Database* db); + + bool DeleteRecord(sql::Database* db, const uint64_t id); + + private: + std::string GetIdColumnName(); + + const char* table_name_ = "contribution_queue"; + const int minimum_version_ = 9; + std::unique_ptr publishers_; +}; + +} // namespace brave_rewards + +#endif // BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_DATABASE_DATABASE_CONTRIBUTION_QUEUE_H_ diff --git a/components/brave_rewards/browser/database/database_contribution_queue_publishers.cc b/components/brave_rewards/browser/database/database_contribution_queue_publishers.cc new file mode 100644 index 000000000000..b26709d22917 --- /dev/null +++ b/components/brave_rewards/browser/database/database_contribution_queue_publishers.cc @@ -0,0 +1,124 @@ +/* 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/. */ + +#include "brave/components/brave_rewards/browser/database/database_contribution_queue_publishers.h" + +#include +#include + +#include "base/bind.h" +#include "base/strings/stringprintf.h" +#include "sql/statement.h" +#include "sql/transaction.h" + +namespace brave_rewards { + +DatabaseContributionQueuePublishers::DatabaseContributionQueuePublishers( + int current_db_version) : DatabaseTable(current_db_version) { +} + +DatabaseContributionQueuePublishers::~DatabaseContributionQueuePublishers() { +} + +bool DatabaseContributionQueuePublishers::Init(sql::Database* db) { + if (GetCurrentDBVersion() < minimum_version_) { + return true; + } + + bool success = CreateTable(db); + return success; +} + +bool DatabaseContributionQueuePublishers::CreateTable(sql::Database* db) { + if (db->DoesTableExist(table_name_)) { + return true; + } + + const std::string query = base::StringPrintf( + "CREATE TABLE %s (" + "%s_id INTEGER NOT NULL," + "publisher_key TEXT NOT NULL," + "amount_percent DOUBLE NOT NULL," + "CONSTRAINT fk_%s_publisher_key " + " FOREIGN KEY (publisher_key) " + " REFERENCES publisher_info (publisher_id)," + "CONSTRAINT fk_%s_id " + " FOREIGN KEY (%s_id) " + " REFERENCES %s (%s_id) " + " ON DELETE CASCADE" + ")", + table_name_, + parent_table_name_, + table_name_, + table_name_, + parent_table_name_, + parent_table_name_, + parent_table_name_); + + return db->Execute(query.c_str()); +} + +bool DatabaseContributionQueuePublishers::CreateIndex(sql::Database* db) { + return true; +} + +bool DatabaseContributionQueuePublishers::InsertOrUpdate( + sql::Database* db, + ledger::ContributionQueuePtr info) { + if (!info) { + return false; + } + + const std::string query = base::StringPrintf( + "INSERT OR REPLACE INTO %s (%s_id, publisher_key, amount_percent) " + "VALUES (?, ?, ?)", + table_name_, + parent_table_name_); + + sql::Transaction transaction(db); + if (!transaction.Begin()) { + return false; + } + + for (const auto& publisher : info->publishers) { + sql::Statement statement( + db->GetCachedStatement(SQL_FROM_HERE, query.c_str())); + + statement.BindInt64(0, info->id); + statement.BindString(1, publisher->publisher_key); + statement.BindDouble(2, publisher->amount_percent); + statement.Run(); + } + + return transaction.Commit(); +} + +ledger::ContributionQueuePublisherList +DatabaseContributionQueuePublishers::GetRecords( + sql::Database* db, + const uint64_t queue_id) { + ledger::ContributionQueuePublisherList list; + const std::string query = base::StringPrintf( + "SELECT publisher_key, amount_percent " + "FROM %s WHERE %s_id = ?", + table_name_, + parent_table_name_); + + sql::Statement statement(db->GetUniqueStatement(query.c_str())); + statement.BindInt64(0, queue_id); + + while (statement.Step()) { + ledger::ContributionQueuePublisherPtr publisher = + ledger::ContributionQueuePublisher::New(); + + publisher->publisher_key = statement.ColumnString(0); + publisher->amount_percent = statement.ColumnDouble(1); + list.push_back(std::move(publisher)); + } + + return list; +} + +} // namespace brave_rewards diff --git a/components/brave_rewards/browser/database/database_contribution_queue_publishers.h b/components/brave_rewards/browser/database/database_contribution_queue_publishers.h new file mode 100644 index 000000000000..0e7f2b9f5eb5 --- /dev/null +++ b/components/brave_rewards/browser/database/database_contribution_queue_publishers.h @@ -0,0 +1,44 @@ +/* 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 BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_DATABASE_DATABASE_CONTRIBUTION_QUEUE_PUBLISHERS_H_ +#define BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_DATABASE_DATABASE_CONTRIBUTION_QUEUE_PUBLISHERS_H_ + +#include +#include + +#include "bat/ledger/mojom_structs.h" +#include "brave/components/brave_rewards/browser/database/database_table.h" + +namespace brave_rewards { + +class DatabaseContributionQueuePublishers: public DatabaseTable { + public: + explicit DatabaseContributionQueuePublishers(int current_db_version); + ~DatabaseContributionQueuePublishers() override; + + bool Init(sql::Database* db) override; + + bool CreateTable(sql::Database* db) override; + + bool CreateIndex(sql::Database* db) override; + + bool InsertOrUpdate( + sql::Database* db, + ledger::ContributionQueuePtr info); + + ledger::ContributionQueuePublisherList GetRecords( + sql::Database* db, + const uint64_t queue_id); + + private: + const char* table_name_ = "contribution_queue_publishers"; + const int minimum_version_ = 9; + const char* parent_table_name_ = "contribution_queue"; +}; + +} // namespace brave_rewards + +#endif // BRAVE_COMPONENTS_BRAVE_REWARDS_BROWSER_DATABASE_DATABASE_CONTRIBUTION_QUEUE_PUBLISHERS_H_ diff --git a/components/brave_rewards/browser/database/publisher_info_database.cc b/components/brave_rewards/browser/database/publisher_info_database.cc index fb3a73fba485..8c8d1b48c345 100644 --- a/components/brave_rewards/browser/database/publisher_info_database.cc +++ b/components/brave_rewards/browser/database/publisher_info_database.cc @@ -25,7 +25,7 @@ namespace brave_rewards { namespace { -const int kCurrentVersionNumber = 8; +const int kCurrentVersionNumber = 9; const int kCompatibleVersionNumber = 1; } // namespace @@ -40,6 +40,9 @@ PublisherInfoDatabase::PublisherInfoDatabase( server_publisher_info_ = std::make_unique(GetCurrentVersion()); + + contribution_queue_ = + std::make_unique(GetCurrentVersion()); } PublisherInfoDatabase::~PublisherInfoDatabase() { @@ -84,6 +87,10 @@ bool PublisherInfoDatabase::Init() { return false; } + if (!contribution_queue_->Init(&GetDB())) { + return false; + } + // Version check. sql::InitStatus version_status = EnsureCurrentVersion(); if (version_status != sql::INIT_OK) { @@ -1078,6 +1085,52 @@ ledger::ServerPublisherInfoPtr PublisherInfoDatabase::GetServerPublisherInfo( return server_publisher_info_->GetRecord(&GetDB(), publisher_key); } +/** + * + * CONTRIBUTION QUEUE + * + */ +bool PublisherInfoDatabase::InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + bool initialized = Init(); + DCHECK(initialized); + + if (!initialized) { + return false; + } + + return contribution_queue_->InsertOrUpdate(&GetDB(), std::move(info)); +} + +ledger::ContributionQueuePtr +PublisherInfoDatabase::GetFirstContributionQueue() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + bool initialized = Init(); + DCHECK(initialized); + + if (!initialized) { + return nullptr; + } + + return contribution_queue_->GetFirstRecord(&GetDB()); +} + +bool PublisherInfoDatabase::DeleteContributionQueue(const uint64_t id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + bool initialized = Init(); + DCHECK(initialized); + + if (!initialized) { + return false; + } + + return contribution_queue_->DeleteRecord(&GetDB(), id); +} + // Other ------------------------------------------------------------------- void PublisherInfoDatabase::RecordP3AStats(bool auto_contributions_on) { @@ -1694,6 +1747,12 @@ bool PublisherInfoDatabase::CreateV8PendingContributionsIndex() { "ON pending_contribution (publisher_id)"); } +bool PublisherInfoDatabase::MigrateV8toV9() { + // no need to call any script as database has min version + // contribution queue tables + return true; +} + bool PublisherInfoDatabase::Migrate(int version) { switch (version) { case 2: { @@ -1717,6 +1776,9 @@ bool PublisherInfoDatabase::Migrate(int version) { case 8: { return MigrateV7toV8(); } + case 9: { + return MigrateV8toV9(); + } default: return false; } diff --git a/components/brave_rewards/browser/database/publisher_info_database.h b/components/brave_rewards/browser/database/publisher_info_database.h index 449031cde302..32f3d3d671e8 100644 --- a/components/brave_rewards/browser/database/publisher_info_database.h +++ b/components/brave_rewards/browser/database/publisher_info_database.h @@ -20,6 +20,7 @@ #include "base/sequence_checker.h" #include "bat/ledger/mojom_structs.h" #include "brave/components/brave_rewards/browser/contribution_info.h" +#include "brave/components/brave_rewards/browser/database/database_contribution_queue.h" #include "brave/components/brave_rewards/browser/database/database_server_publisher_info.h" #include "brave/components/brave_rewards/browser/pending_contribution.h" #include "brave/components/brave_rewards/browser/recurring_donation.h" @@ -102,6 +103,12 @@ class PublisherInfoDatabase { ledger::ServerPublisherInfoPtr GetServerPublisherInfo( const std::string& publisher_key); + bool InsertOrUpdateContributionQueue(ledger::ContributionQueuePtr info); + + ledger::ContributionQueuePtr GetFirstContributionQueue(); + + bool DeleteContributionQueue(const uint64_t id); + void RecordP3AStats(bool auto_contributions_on); // Returns the current version of the publisher info database @@ -170,6 +177,8 @@ class PublisherInfoDatabase { bool CreateV8PendingContributionsTable(); bool CreateV8PendingContributionsIndex(); + bool MigrateV8toV9(); + bool Migrate(int version); bool MigrateDBTable( @@ -200,6 +209,7 @@ class PublisherInfoDatabase { std::unique_ptr memory_pressure_listener_; std::unique_ptr server_publisher_info_; + std::unique_ptr contribution_queue_; SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(PublisherInfoDatabase); diff --git a/components/brave_rewards/browser/database/publisher_info_database_unittest.cc b/components/brave_rewards/browser/database/publisher_info_database_unittest.cc index 5dbef7266568..d2c1d068de35 100644 --- a/components/brave_rewards/browser/database/publisher_info_database_unittest.cc +++ b/components/brave_rewards/browser/database/publisher_info_database_unittest.cc @@ -1158,6 +1158,18 @@ TEST_F(PublisherInfoDatabaseTest, Migrationv7tov8_PendingContribution) { static_cast(pending_contribution->type)); } +TEST_F(PublisherInfoDatabaseTest, Migrationv8tov9) { + base::ScopedTempDir temp_dir; + base::FilePath db_file; + CreateMigrationDatabase(&temp_dir, &db_file, 8, 9); + EXPECT_TRUE(publisher_info_database_->Init()); + + EXPECT_EQ(publisher_info_database_->GetTableVersionNumber(), 9); + + const std::string schema = publisher_info_database_->GetSchema(); + EXPECT_EQ(schema, GetSchemaString(9)); +} + TEST_F(PublisherInfoDatabaseTest, DeleteActivityInfo) { base::ScopedTempDir temp_dir; base::FilePath db_file; diff --git a/components/brave_rewards/browser/rewards_service_browsertest.cc b/components/brave_rewards/browser/rewards_service_browsertest.cc index a538b83e4f79..13cd2729c363 100644 --- a/components/brave_rewards/browser/rewards_service_browsertest.cc +++ b/components/brave_rewards/browser/rewards_service_browsertest.cc @@ -333,7 +333,10 @@ class BraveRewardsBrowserTest : "[" "[\"bumpsmack.com\",\"publisher_verified\",false,\"address1\",{}]," "[\"duckduckgo.com\",\"wallet_connected\",false,\"address2\",{}]," - "[\"3zsistemi.si\",\"wallet_connected\",false,\"address3\",{}]" + "[\"3zsistemi.si\",\"wallet_connected\",false,\"address3\",{}]," + "[\"site1.com\",\"wallet_connected\",false,\"address4\",{}]," + "[\"site2.com\",\"wallet_connected\",false,\"address5\",{}]," + "[\"site3.com\",\"wallet_connected\",false,\"address6\",{}]" "]"; } } else if (base::StartsWith( @@ -990,11 +993,13 @@ class BraveRewardsBrowserTest : rewards_service()->StartMonthlyContributionForTest(); // Wait for reconciliation to complete - WaitForTipReconcileCompleted(); - const auto result = should_contribute - ? ledger::Result::LEDGER_OK - : ledger::Result::RECURRING_TABLE_EMPTY; - ASSERT_EQ(tip_reconcile_status_, result); + if (should_contribute) { + WaitForTipReconcileCompleted(); + const auto result = should_contribute + ? ledger::Result::LEDGER_OK + : ledger::Result::RECURRING_TABLE_EMPTY; + ASSERT_EQ(tip_reconcile_status_, result); + } // Signal that monthly contribution was made and update wallet // with new balance @@ -1210,6 +1215,21 @@ class BraveRewardsBrowserTest : AsWeakPtr())); } + void TipViaCode( + const std::string publisher_key, + int amount, + bool recurring, + ledger::PublisherStatus status) { + auto site = std::make_unique(); + site->id = publisher_key; + site->name = publisher_key; + site->url = publisher_key; + site->status = static_cast(status); + site->provider = ""; + site->favicon_url = ""; + rewards_service_->OnTip(publisher_key, amount, recurring, std::move(site)); + } + const std::vector tip_amounts_ = {1.0, 5.0, 10.0}; MOCK_METHOD1(OnGetProduction, void(bool)); @@ -2505,7 +2525,7 @@ IN_PROC_BROWSER_TEST_F(BraveRewardsBrowserTest, VisitPublisher("duckduckgo.com", verified); VisitPublisher("brave.com", !verified); - // Tip publisher + // Set monthly recurring rewards_service_->OnTip("duckduckgo.com", 25, true); // Trigger contribution process @@ -2521,29 +2541,64 @@ IN_PROC_BROWSER_TEST_F(BraveRewardsBrowserTest, // Make sure that balance is updated correctly { - content::EvalJsResult js_result = EvalJs( - contents(), - "const delay = t => new Promise(resolve => setTimeout(resolve, t));" - "delay(1000).then(() => " - " " - "document.querySelector(\"[data-test-id='balance']\").innerText);", - content::EXECUTE_SCRIPT_DEFAULT_OPTIONS, - content::ISOLATED_WORLD_ID_CONTENT_END); - EXPECT_NE(js_result.ExtractString().find(GetBalance() + " BAT"), - std::string::npos); + const std::string result = RewardsPageBalance(); + EXPECT_NE(result.find(ExpectedBalanceString()), std::string::npos); } // Check that summary table shows the appropriate contribution { - content::EvalJsResult js_result = EvalJs( - contents(), - "const delay = t => new Promise(resolve => setTimeout(resolve, t));" - "delay(0).then(() => " - " document.querySelector(\"[color='contribute']\").innerText);", - content::EXECUTE_SCRIPT_DEFAULT_OPTIONS, - content::ISOLATED_WORLD_ID_CONTENT_END); - EXPECT_NE(js_result.ExtractString().find("-5.0BAT"), - std::string::npos); + const std::string result = ElementInnerText("[color='contribute']"); + EXPECT_NE(result.find("-5.0BAT"), std::string::npos); + } + + // Stop observing the Rewards service + rewards_service_->RemoveObserver(this); +} + +IN_PROC_BROWSER_TEST_F(BraveRewardsBrowserTest, + MultipleRecurringOverBudgetAndPartialAutoContribution) { + // Observe the Rewards service + rewards_service_->AddObserver(this); + + // Enable Rewards + EnableRewards(); + + // Claim grant using panel (30 BAT) + const bool use_panel = true; + ClaimGrant(use_panel); + + // Visit verified publisher + const bool verified = true; + VisitPublisher("duckduckgo.com", verified); + + // Set monthly recurring + rewards_service_->OnTip("duckduckgo.com", 5, true); + + TipViaCode("site1.com", 10, true, ledger::PublisherStatus::VERIFIED); + TipViaCode("site2.com", 10, true, ledger::PublisherStatus::VERIFIED); + TipViaCode("site3.com", 10, true, ledger::PublisherStatus::VERIFIED); + + // Trigger contribution process + rewards_service()->StartMonthlyContributionForTest(); + + // Wait for reconciliation to complete + WaitForMultipleTipReconcileCompleted(3); + ASSERT_EQ(tip_reconcile_status_, ledger::Result::LEDGER_OK); + + // Wait for reconciliation to complete successfully + WaitForACReconcileCompleted(); + ASSERT_EQ(ac_reconcile_status_, ledger::Result::LEDGER_OK); + + // Make sure that balance is updated correctly + { + const std::string result = RewardsPageBalance(); + EXPECT_NE(result.find(ExpectedBalanceString()), std::string::npos); + } + + // Check that summary table shows the appropriate contribution + { + const std::string result = ElementInnerText("[color='contribute']"); + EXPECT_NE(result.find("-5.0BAT"), std::string::npos); } // Stop observing the Rewards service diff --git a/components/brave_rewards/browser/rewards_service_impl.cc b/components/brave_rewards/browser/rewards_service_impl.cc index 526fea57f176..5801ab8120f7 100644 --- a/components/brave_rewards/browser/rewards_service_impl.cc +++ b/components/brave_rewards/browser/rewards_service_impl.cc @@ -535,6 +535,12 @@ void RewardsServiceImpl::StartLedger() { bat_ledger_->Initialize(std::move(callback)); } +void RewardsServiceImpl::OnResult( + ledger::ResultCallback callback, + const ledger::Result result) { + callback(result); +} + void RewardsServiceImpl::MaybeShowBackupNotification(uint64_t boot_stamp) { PrefService* pref_service = profile_->GetPrefs(); bool user_has_funded = pref_service->GetBoolean(prefs::kRewardsUserHasFunded); @@ -2954,15 +2960,15 @@ void RewardsServiceImpl::OnTip( void RewardsServiceImpl::OnTip( const std::string& publisher_key, - int amount, - bool recurring, + const int amount, + const bool recurring, std::unique_ptr site) { if (!site) { return; } - ledger::PublisherInfoPtr info; + auto info = ledger::PublisherInfo::New(); info->id = publisher_key; info->status = static_cast(site->status); info->excluded = ledger::PublisherExclude::DEFAULT; @@ -4020,4 +4026,84 @@ bool RewardsServiceImpl::ShouldUseStagingServerForAndroid() { } #endif +ledger::Result InsertOrUpdateContributionQueueOnFileTaskRunner( + PublisherInfoDatabase* backend, + ledger::ContributionQueuePtr info) { + if (!backend) { + return ledger::Result::LEDGER_ERROR; + } + + const bool result = backend->InsertOrUpdateContributionQueue(std::move(info)); + + return result ? ledger::Result::LEDGER_OK : ledger::Result::LEDGER_ERROR; +} + +void RewardsServiceImpl::InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + ledger::ResultCallback callback) { + ledger::ContributionQueuePtr info_clone = info->Clone(); + base::PostTaskAndReplyWithResult( + file_task_runner_.get(), + FROM_HERE, + base::BindOnce(&InsertOrUpdateContributionQueueOnFileTaskRunner, + publisher_info_backend_.get(), + std::move(info_clone)), + base::BindOnce(&RewardsServiceImpl::OnResult, + AsWeakPtr(), + callback)); +} + +ledger::Result DeleteContributionQueueOnFileTaskRunner( + PublisherInfoDatabase* backend, + const uint64_t id) { + if (!backend) { + return ledger::Result::LEDGER_ERROR; + } + + const bool result = backend->DeleteContributionQueue(id); + + return result ? ledger::Result::LEDGER_OK : ledger::Result::LEDGER_ERROR; +} + +void RewardsServiceImpl::DeleteContributionQueue( + const uint64_t id, + ledger::ResultCallback callback) { + base::PostTaskAndReplyWithResult( + file_task_runner_.get(), + FROM_HERE, + base::BindOnce(&DeleteContributionQueueOnFileTaskRunner, + publisher_info_backend_.get(), + id), + base::BindOnce(&RewardsServiceImpl::OnResult, + AsWeakPtr(), + callback)); +} + +ledger::ContributionQueuePtr GetFirstContributionQueueOnFileTaskRunner( + PublisherInfoDatabase* backend) { + if (!backend) { + return nullptr; + } + + return backend->GetFirstContributionQueue(); +} + +void RewardsServiceImpl::GetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback) { + base::PostTaskAndReplyWithResult( + file_task_runner_.get(), + FROM_HERE, + base::BindOnce(&GetFirstContributionQueueOnFileTaskRunner, + publisher_info_backend_.get()), + base::BindOnce(&RewardsServiceImpl::OnGetFirstContributionQueue, + AsWeakPtr(), + callback)); +} + +void RewardsServiceImpl::OnGetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback, + ledger::ContributionQueuePtr info) { + callback(std::move(info)); +} + } // namespace brave_rewards diff --git a/components/brave_rewards/browser/rewards_service_impl.h b/components/brave_rewards/browser/rewards_service_impl.h index f25507a3dcaa..91f3851e2cc2 100644 --- a/components/brave_rewards/browser/rewards_service_impl.h +++ b/components/brave_rewards/browser/rewards_service_impl.h @@ -258,6 +258,12 @@ class RewardsServiceImpl : public RewardsService, int amount, bool recurring) override; + void OnTip( + const std::string& publisher_key, + const int amount, + const bool recurring, + std::unique_ptr site) override; + void SetPublisherMinVisitTime(uint64_t duration_in_seconds) const override; void FetchBalance(FetchBalanceCallback callback) override; @@ -297,6 +303,9 @@ class RewardsServiceImpl : public RewardsService, FRIEND_TEST_ALL_PREFIXES(RewardsServiceTest, OnWalletProperties); const base::OneShotEvent& ready() const { return ready_; } + + void OnResult(ledger::ResultCallback callback, const ledger::Result result); + void OnCreateWallet(CreateWalletCallback callback, ledger::Result result); void OnLedgerStateSaved(ledger::LedgerCallbackHandler* handler, @@ -374,8 +383,6 @@ class RewardsServiceImpl : public RewardsService, void OnWalletProperties( const ledger::Result result, ledger::WalletPropertiesPtr properties) override; - void OnTip(const std::string& publisher_key, int amount, bool recurring, - std::unique_ptr site) override; void DeleteActivityInfo( const std::string& publisher_key, @@ -662,6 +669,17 @@ class RewardsServiceImpl : public RewardsService, const std::string& wallet_type, const std::string& id) override; + void InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + ledger::ResultCallback callback) override; + + void DeleteContributionQueue( + const uint64_t id, + ledger::ResultCallback callback) override; + + void GetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback) override; + // end ledger::LedgerClient // Mojo Proxy methods @@ -709,6 +727,10 @@ class RewardsServiceImpl : public RewardsService, void RecordBackendP3AStats() const; + void OnGetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback, + ledger::ContributionQueuePtr info); + #if defined(OS_ANDROID) bool ShouldUseStagingServerForAndroid(); void CreateWalletAttestationResult( diff --git a/components/services/bat_ledger/bat_ledger_client_mojo_proxy.cc b/components/services/bat_ledger/bat_ledger_client_mojo_proxy.cc index 92951bbc04b9..42d66f0b9551 100644 --- a/components/services/bat_ledger/bat_ledger_client_mojo_proxy.cc +++ b/components/services/bat_ledger/bat_ledger_client_mojo_proxy.cc @@ -58,6 +58,10 @@ class LogStreamImpl : public ledger::LogStream { DISALLOW_COPY_AND_ASSIGN(LogStreamImpl); }; +void OnResultCallback(ledger::ResultCallback callback, ledger::Result result) { + callback(result); +} + void OnSaveState(const ledger::OnSaveCallback& callback, const ledger::Result result) { callback(result); @@ -948,4 +952,32 @@ void BatLedgerClientMojoProxy::RemoveTransferFee( bat_ledger_client_->RemoveTransferFee(wallet_type, id); } +void BatLedgerClientMojoProxy::InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + ledger::ResultCallback callback) { + bat_ledger_client_->InsertOrUpdateContributionQueue( + std::move(info), + base::BindOnce(&OnResultCallback, std::move(callback))); +} + +void BatLedgerClientMojoProxy::DeleteContributionQueue( + const uint64_t id, + ledger::ResultCallback callback) { + bat_ledger_client_->DeleteContributionQueue( + id, + base::BindOnce(&OnResultCallback, std::move(callback))); +} + +void OnGetFirstContributionQueue( + const ledger::GetFirstContributionQueueCallback& callback, + ledger::ContributionQueuePtr info) { + callback(std::move(info)); +} + +void BatLedgerClientMojoProxy::GetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback) { + bat_ledger_client_->GetFirstContributionQueue( + base::BindOnce(&OnGetFirstContributionQueue, std::move(callback))); +} + } // namespace bat_ledger diff --git a/components/services/bat_ledger/bat_ledger_client_mojo_proxy.h b/components/services/bat_ledger/bat_ledger_client_mojo_proxy.h index 6aea1a204f45..b984af0e575e 100644 --- a/components/services/bat_ledger/bat_ledger_client_mojo_proxy.h +++ b/components/services/bat_ledger/bat_ledger_client_mojo_proxy.h @@ -201,6 +201,17 @@ class BatLedgerClientMojoProxy : public ledger::LedgerClient, const std::string& wallet_type, const std::string& id) override; + void InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + ledger::ResultCallback callback) override; + + void DeleteContributionQueue( + const uint64_t id, + ledger::ResultCallback callback) override; + + void GetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback) override; + private: bool Connected() const; diff --git a/components/services/bat_ledger/public/cpp/ledger_client_mojo_proxy.cc b/components/services/bat_ledger/public/cpp/ledger_client_mojo_proxy.cc index 1688d7df4c7d..487acc615666 100644 --- a/components/services/bat_ledger/public/cpp/ledger_client_mojo_proxy.cc +++ b/components/services/bat_ledger/public/cpp/ledger_client_mojo_proxy.cc @@ -975,4 +975,74 @@ void LedgerClientMojoProxy::RemoveTransferFee( ledger_client_->RemoveTransferFee(wallet_type, id); } +// static +void LedgerClientMojoProxy::OnInsertOrUpdateContributionQueue( + CallbackHolder* holder, + const ledger::Result result) { + DCHECK(holder); + if (holder->is_valid()) { + std::move(holder->get()).Run(result); + } + delete holder; +} + +void LedgerClientMojoProxy::InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + InsertOrUpdateContributionQueueCallback callback) { + auto* holder = new CallbackHolder( + AsWeakPtr(), + std::move(callback)); + ledger_client_->InsertOrUpdateContributionQueue( + std::move(info), + std::bind(LedgerClientMojoProxy::OnInsertOrUpdateContributionQueue, + holder, + _1)); +} + +// static +void LedgerClientMojoProxy::OnDeleteContributionQueue( + CallbackHolder* holder, + const ledger::Result result) { + DCHECK(holder); + if (holder->is_valid()) { + std::move(holder->get()).Run(result); + } + delete holder; +} + +void LedgerClientMojoProxy::DeleteContributionQueue( + const uint64_t id, + DeleteContributionQueueCallback callback) { + auto* holder = new CallbackHolder( + AsWeakPtr(), + std::move(callback)); + ledger_client_->DeleteContributionQueue( + id, + std::bind(LedgerClientMojoProxy::OnDeleteContributionQueue, + holder, + _1)); +} + +// static +void LedgerClientMojoProxy::OnGetFirstContributionQueue( + CallbackHolder* holder, + ledger::ContributionQueuePtr info) { + DCHECK(holder); + if (holder->is_valid()) { + std::move(holder->get()).Run(std::move(info)); + } + delete holder; +} + +void LedgerClientMojoProxy::GetFirstContributionQueue( + GetFirstContributionQueueCallback callback) { + auto* holder = new CallbackHolder( + AsWeakPtr(), + std::move(callback)); + ledger_client_->GetFirstContributionQueue( + std::bind(LedgerClientMojoProxy::OnGetFirstContributionQueue, + holder, + _1)); +} + } // namespace bat_ledger diff --git a/components/services/bat_ledger/public/cpp/ledger_client_mojo_proxy.h b/components/services/bat_ledger/public/cpp/ledger_client_mojo_proxy.h index bfd6b8df338f..79b00078f0db 100644 --- a/components/services/bat_ledger/public/cpp/ledger_client_mojo_proxy.h +++ b/components/services/bat_ledger/public/cpp/ledger_client_mojo_proxy.h @@ -221,6 +221,17 @@ class LedgerClientMojoProxy : public mojom::BatLedgerClient, const std::string& wallet_type, const std::string& id) override; + void InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + InsertOrUpdateContributionQueueCallback callback) override; + + void DeleteContributionQueue( + const uint64_t id, + DeleteContributionQueueCallback callback) override; + + void GetFirstContributionQueue( + GetFirstContributionQueueCallback callback) override; + private: // workaround to pass base::OnceCallback into std::bind // also serves as a wrapper for passing ledger::LedgerCallbackHandler* @@ -389,6 +400,18 @@ class LedgerClientMojoProxy : public mojom::BatLedgerClient, CallbackHolder* holder, ledger::ServerPublisherInfoPtr info); + static void OnInsertOrUpdateContributionQueue( + CallbackHolder* holder, + const ledger::Result result); + + static void OnDeleteContributionQueue( + CallbackHolder* holder, + const ledger::Result result); + + static void OnGetFirstContributionQueue( + CallbackHolder* holder, + ledger::ContributionQueuePtr info); + ledger::LedgerClient* ledger_client_; DISALLOW_COPY_AND_ASSIGN(LedgerClientMojoProxy); diff --git a/components/services/bat_ledger/public/interfaces/bat_ledger.mojom b/components/services/bat_ledger/public/interfaces/bat_ledger.mojom index d50b852233a3..8f7598a33163 100644 --- a/components/services/bat_ledger/public/interfaces/bat_ledger.mojom +++ b/components/services/bat_ledger/public/interfaces/bat_ledger.mojom @@ -291,4 +291,7 @@ interface BatLedgerClient { GetTransferFees(string wallet_type) => (map list); SetTransferFee(string wallet_type, ledger.mojom.TransferFee transfer_fee); RemoveTransferFee(string wallet_type, string id); + InsertOrUpdateContributionQueue(ledger.mojom.ContributionQueue info) => (ledger.mojom.Result result); + DeleteContributionQueue(uint64 id) => (ledger.mojom.Result result); + GetFirstContributionQueue() => (ledger.mojom.ContributionQueue? info); }; diff --git a/test/data/rewards-data/migration/publisher_info_db_v8 b/test/data/rewards-data/migration/publisher_info_db_v8 new file mode 100644 index 000000000000..31d89b2dc53c Binary files /dev/null and b/test/data/rewards-data/migration/publisher_info_db_v8 differ diff --git a/test/data/rewards-data/migration/publisher_info_schema_v9.txt b/test/data/rewards-data/migration/publisher_info_schema_v9.txt new file mode 100644 index 000000000000..c84d77a552c2 --- /dev/null +++ b/test/data/rewards-data/migration/publisher_info_schema_v9.txt @@ -0,0 +1,31 @@ +index|activity_info_publisher_id_index|activity_info|CREATE INDEX activity_info_publisher_id_index ON activity_info (publisher_id) +index|contribution_info_publisher_id_index|contribution_info|CREATE INDEX contribution_info_publisher_id_index ON contribution_info (publisher_id) +index|pending_contribution_publisher_id_index|pending_contribution|CREATE INDEX pending_contribution_publisher_id_index ON pending_contribution (publisher_id) +index|recurring_donation_publisher_id_index|recurring_donation|CREATE INDEX recurring_donation_publisher_id_index ON recurring_donation (publisher_id) +index|server_publisher_amounts_publisher_key_index|server_publisher_amounts|CREATE INDEX server_publisher_amounts_publisher_key_index ON server_publisher_amounts (publisher_key) +index|server_publisher_banner_publisher_key_index|server_publisher_banner|CREATE INDEX server_publisher_banner_publisher_key_index ON server_publisher_banner (publisher_key) +index|server_publisher_info_publisher_key_index|server_publisher_info|CREATE INDEX server_publisher_info_publisher_key_index ON server_publisher_info (publisher_key) +index|server_publisher_links_publisher_key_index|server_publisher_links|CREATE INDEX server_publisher_links_publisher_key_index ON server_publisher_links (publisher_key) +index|sqlite_autoindex_activity_info_1|activity_info| +index|sqlite_autoindex_media_publisher_info_1|media_publisher_info| +index|sqlite_autoindex_meta_1|meta| +index|sqlite_autoindex_publisher_info_1|publisher_info| +index|sqlite_autoindex_recurring_donation_1|recurring_donation| +index|sqlite_autoindex_server_publisher_amounts_1|server_publisher_amounts| +index|sqlite_autoindex_server_publisher_banner_1|server_publisher_banner| +index|sqlite_autoindex_server_publisher_info_1|server_publisher_info| +index|sqlite_autoindex_server_publisher_links_1|server_publisher_links| +table|activity_info|activity_info|CREATE TABLE activity_info(publisher_id LONGVARCHAR NOT NULL,duration INTEGER DEFAULT 0 NOT NULL,visits INTEGER DEFAULT 0 NOT NULL,score DOUBLE DEFAULT 0 NOT NULL,percent INTEGER DEFAULT 0 NOT NULL,weight DOUBLE DEFAULT 0 NOT NULL,reconcile_stamp INTEGER DEFAULT 0 NOT NULL,CONSTRAINT activity_unique UNIQUE (publisher_id, reconcile_stamp) CONSTRAINT fk_activity_info_publisher_id FOREIGN KEY (publisher_id) REFERENCES "publisher_info_old" (publisher_id) ON DELETE CASCADE) +table|contribution_info|contribution_info|CREATE TABLE contribution_info(publisher_id LONGVARCHAR,probi TEXT "0" NOT NULL,date INTEGER NOT NULL,type INTEGER NOT NULL,month INTEGER NOT NULL,year INTEGER NOT NULL,CONSTRAINT fk_contribution_info_publisher_id FOREIGN KEY (publisher_id) REFERENCES publisher_info (publisher_id) ON DELETE CASCADE) +table|contribution_queue|contribution_queue|CREATE TABLE contribution_queue (contribution_queue_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,type INTEGER NOT NULL,amount DOUBLE NOT NULL,partial INTEGER NOT NULL DEFAULT 0,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL) +table|contribution_queue_publishers|contribution_queue_publishers|CREATE TABLE contribution_queue_publishers (contribution_queue_id INTEGER NOT NULL,publisher_key TEXT NOT NULL,amount_percent DOUBLE NOT NULL,CONSTRAINT fk_contribution_queue_publishers_publisher_key FOREIGN KEY (publisher_key) REFERENCES publisher_info (publisher_id),CONSTRAINT fk_contribution_queue_publishers_id FOREIGN KEY (contribution_queue_id) REFERENCES contribution_queue (contribution_queue_id) ON DELETE CASCADE) +table|media_publisher_info|media_publisher_info|CREATE TABLE media_publisher_info(media_key TEXT NOT NULL PRIMARY KEY UNIQUE,publisher_id LONGVARCHAR NOT NULL,CONSTRAINT fk_media_publisher_info_publisher_id FOREIGN KEY (publisher_id) REFERENCES "publisher_info_old" (publisher_id) ON DELETE CASCADE) +table|meta|meta|CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR) +table|pending_contribution|pending_contribution|CREATE TABLE pending_contribution(publisher_id LONGVARCHAR NOT NULL,amount DOUBLE DEFAULT 0 NOT NULL,added_date INTEGER DEFAULT 0 NOT NULL,viewing_id LONGVARCHAR NOT NULL,type INTEGER NOT NULL,CONSTRAINT fk_pending_contribution_publisher_id FOREIGN KEY (publisher_id) REFERENCES publisher_info (publisher_id) ON DELETE CASCADE) +table|publisher_info|publisher_info|CREATE TABLE publisher_info(publisher_id LONGVARCHAR PRIMARY KEY NOT NULL UNIQUE,excluded INTEGER DEFAULT 0 NOT NULL,name TEXT NOT NULL,favIcon TEXT NOT NULL,url TEXT NOT NULL,provider TEXT NOT NULL) +table|recurring_donation|recurring_donation|CREATE TABLE recurring_donation(publisher_id LONGVARCHAR NOT NULL PRIMARY KEY UNIQUE,amount DOUBLE DEFAULT 0 NOT NULL,added_date INTEGER DEFAULT 0 NOT NULL,CONSTRAINT fk_recurring_donation_publisher_id FOREIGN KEY (publisher_id) REFERENCES "publisher_info_old" (publisher_id) ON DELETE CASCADE) +table|server_publisher_amounts|server_publisher_amounts|CREATE TABLE server_publisher_amounts (publisher_key LONGVARCHAR NOT NULL,amount DOUBLE DEFAULT 0 NOT NULL,CONSTRAINT server_publisher_amounts_unique UNIQUE (publisher_key, amount) CONSTRAINT fk_server_publisher_amounts_publisher_key FOREIGN KEY (publisher_key) REFERENCES server_publisher_info (publisher_key) ON DELETE CASCADE) +table|server_publisher_banner|server_publisher_banner|CREATE TABLE server_publisher_banner (publisher_key LONGVARCHAR PRIMARY KEY NOT NULL UNIQUE,title TEXT,description TEXT,background TEXT,logo TEXT,CONSTRAINT fk_server_publisher_banner_publisher_key FOREIGN KEY (publisher_key) REFERENCES server_publisher_info (publisher_key) ON DELETE CASCADE) +table|server_publisher_info|server_publisher_info|CREATE TABLE server_publisher_info (publisher_key LONGVARCHAR PRIMARY KEY NOT NULL UNIQUE,status INTEGER DEFAULT 0 NOT NULL,excluded INTEGER DEFAULT 0 NOT NULL,address TEXT NOT NULL) +table|server_publisher_links|server_publisher_links|CREATE TABLE server_publisher_links (publisher_key LONGVARCHAR NOT NULL,provider TEXT,link TEXT,CONSTRAINT server_publisher_links_unique UNIQUE (publisher_key, provider) CONSTRAINT fk_server_publisher_links_publisher_key FOREIGN KEY (publisher_key) REFERENCES server_publisher_info (publisher_key) ON DELETE CASCADE) +table|sqlite_sequence|sqlite_sequence|CREATE TABLE sqlite_sequence(name,seq) diff --git a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_client_mock.h b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_client_mock.h index 42f35c972a77..49606815ba77 100644 --- a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_client_mock.h +++ b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_client_mock.h @@ -359,6 +359,17 @@ class MockConfirmationsClient : public ConfirmationsClient { MOCK_METHOD2(RemoveTransferFee, void( const std::string& wallet_type, const std::string& id)); + + MOCK_METHOD2(InsertOrUpdateContributionQueue, void( + ledger::ContributionQueuePtr info, + ledger::ResultCallback callback)); + + MOCK_METHOD2(DeleteContributionQueue, void( + const uint64_t id, + ledger::ResultCallback callback)); + + MOCK_METHOD1(GetFirstContributionQueue, void( + ledger::GetFirstContributionQueueCallback callback)); }; } // namespace confirmations diff --git a/vendor/bat-native-ledger/BUILD.gn b/vendor/bat-native-ledger/BUILD.gn index 6886ecbf97e5..dfdc2ca65b9e 100644 --- a/vendor/bat-native-ledger/BUILD.gn +++ b/vendor/bat-native-ledger/BUILD.gn @@ -95,8 +95,12 @@ source_set("ledger") { "src/bat/ledger/internal/bignum.h", "src/bat/ledger/internal/grants.cc", "src/bat/ledger/internal/grants.h", + "src/bat/ledger/internal/common/bind_util.cc", + "src/bat/ledger/internal/common/bind_util.h", "src/bat/ledger/internal/contribution/contribution.cc", "src/bat/ledger/internal/contribution/contribution.h", + "src/bat/ledger/internal/contribution/contribution_util.cc", + "src/bat/ledger/internal/contribution/contribution_util.h", "src/bat/ledger/internal/contribution/phase_one.cc", "src/bat/ledger/internal/contribution/phase_one.h", "src/bat/ledger/internal/contribution/phase_two.cc", diff --git a/vendor/bat-native-ledger/include/bat/ledger/ledger_client.h b/vendor/bat-native-ledger/include/bat/ledger/ledger_client.h index 4acf9e556b5b..fd0857d5a4ae 100644 --- a/vendor/bat-native-ledger/include/bat/ledger/ledger_client.h +++ b/vendor/bat-native-ledger/include/bat/ledger/ledger_client.h @@ -69,6 +69,9 @@ using ClearAndInsertServerPublisherListCallback = std::function; using GetServerPublisherInfoCallback = std::function; +using ResultCallback = std::function; +using GetFirstContributionQueueCallback = + std::function; class LEDGER_EXPORT LedgerClient { public: @@ -283,6 +286,17 @@ class LEDGER_EXPORT LedgerClient { virtual void RemoveTransferFee( const std::string& wallet_type, const std::string& id) = 0; + + virtual void InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + ledger::ResultCallback callback) = 0; + + virtual void DeleteContributionQueue( + const uint64_t id, + ledger::ResultCallback callback) = 0; + + virtual void GetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback) = 0; }; } // namespace ledger diff --git a/vendor/bat-native-ledger/include/bat/ledger/mojom_structs.h b/vendor/bat-native-ledger/include/bat/ledger/mojom_structs.h index f76bb849e121..5a67c2353bbd 100644 --- a/vendor/bat-native-ledger/include/bat/ledger/mojom_structs.h +++ b/vendor/bat-native-ledger/include/bat/ledger/mojom_structs.h @@ -34,6 +34,16 @@ using BalanceReportInfoPtr = mojom::BalanceReportInfoPtr; using ContributionInfo = mojom::ContributionInfo; using ContributionInfoPtr = mojom::ContributionInfoPtr; +using ContributionQueue = ledger::mojom::ContributionQueue; +using ContributionQueuePtr = ledger::mojom::ContributionQueuePtr; +using ContributionQueueList = std::vector; + +using ContributionQueuePublisher = ledger::mojom::ContributionQueuePublisher; +using ContributionQueuePublisherPtr = + ledger::mojom::ContributionQueuePublisherPtr; +using ContributionQueuePublisherList = + std::vector; + using ContributionRetry = mojom::ContributionRetry; using ExcludeFilter = mojom::ExcludeFilter; diff --git a/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger.mojom b/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger.mojom index 169dfd2d98e4..95df9efcb89f 100644 --- a/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger.mojom +++ b/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger.mojom @@ -298,4 +298,18 @@ enum WalletStatus { DISCONNECTED_NOT_VERIFIED = 3, DISCONNECTED_VERIFIED = 4, PENDING = 5 +}; + +struct ContributionQueue { + uint64 id; + RewardsType type; + double amount; + bool partial; + + array publishers; +}; + +struct ContributionQueuePublisher { + string publisher_key; + double amount_percent; }; \ No newline at end of file diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.cc index 2f0182c80f1e..5e58947f449a 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.cc @@ -1090,11 +1090,9 @@ bool SURVEYOR_ST::loadFromJson(const std::string & json) { ///////////////////////////////////////////////////////////////////////////// RECONCILE_DIRECTION::RECONCILE_DIRECTION() {} RECONCILE_DIRECTION::RECONCILE_DIRECTION(const std::string& publisher_key, - const int amount, - const std::string& currency) : + const double amount_percent) : publisher_key_(publisher_key), - amount_(amount), - currency_(currency) {} + amount_percent_(amount_percent) {} RECONCILE_DIRECTION::~RECONCILE_DIRECTION() {} bool RECONCILE_DIRECTION::loadFromJson(const std::string & json) { @@ -1104,15 +1102,19 @@ bool RECONCILE_DIRECTION::loadFromJson(const std::string & json) { // has parser errors or wrong types bool error = d.HasParseError(); if (!error) { - error = !(d.HasMember("amount") && d["amount"].IsInt() && - d.HasMember("publisher_key") && d["publisher_key"].IsString() && - d.HasMember("currency") && d["currency"].IsString()); + error = !(d.HasMember("publisher_key") && d["publisher_key"].IsString()); } if (!error) { - amount_ = d["amount"].GetInt(); + if (d.HasMember("amount") && d["amount"].IsInt()) { + amount_percent_ = static_cast(d["amount"].GetInt()); + } else if (d["amount_percent"].IsDouble()) { + amount_percent_ = d["amount_percent"].GetDouble(); + } else { + return false; + } + publisher_key_ = d["publisher_key"].GetString(); - currency_ = d["currency"].GetString(); } return !error; @@ -1121,15 +1123,12 @@ bool RECONCILE_DIRECTION::loadFromJson(const std::string & json) { void saveToJson(JsonWriter* writer, const RECONCILE_DIRECTION& data) { writer->StartObject(); - writer->String("amount"); - writer->Int(data.amount_); + writer->String("amount_percent"); + writer->Double(data.amount_percent_); writer->String("publisher_key"); writer->String(data.publisher_key_.c_str()); - writer->String("currency"); - writer->String(data.currency_.c_str()); - writer->EndObject(); } @@ -1154,7 +1153,6 @@ CURRENT_RECONCILE::CURRENT_RECONCILE(const CURRENT_RECONCILE& data): fee_(data.fee_), directions_(data.directions_), type_(data.type_), - list_(data.list_), retry_step_(data.retry_step_), retry_level_(data.retry_level_), destination_(data.destination_), @@ -1206,28 +1204,25 @@ bool CURRENT_RECONCILE::loadFromJson(const std::string & json) { if (d.HasMember("directions") && d["directions"].IsArray()) { for (auto & i : d["directions"].GetArray()) { - auto obj = i.GetObject(); + rapidjson::StringBuffer sb; + rapidjson::Writer writer(sb); + i.Accept(writer); + RECONCILE_DIRECTION direction; - direction.amount_ = obj["amount"].GetInt(); - direction.publisher_key_ = obj["publisher_key"].GetString(); - direction.currency_ = obj["currency"].GetString(); + direction.loadFromJson(sb.GetString()); directions_.push_back(direction); } } + // LEGACY MIGRATION from publisher object if (d.HasMember("list") && d["list"].IsArray()) { for (auto &i : d["list"].GetArray()) { - PUBLISHER_ST publisher_st; + RECONCILE_DIRECTION direction; auto obj = i.GetObject(); - publisher_st.id_ = obj["id"].GetString(); - publisher_st.duration_ = obj["duration"].GetUint64(); - publisher_st.score_ = obj["score"].GetDouble(); - publisher_st.visits_ = obj["visits"].GetUint(); - publisher_st.percent_ = obj["percent"].GetUint(); - publisher_st.weight_ = obj["weight"].GetDouble(); - - list_.push_back(publisher_st); + direction.publisher_key_ = obj["id"].GetString(); + direction.amount_percent_ = obj["weight"].GetDouble(); + directions_.push_back(direction); } } @@ -1310,13 +1305,6 @@ void saveToJson(JsonWriter* writer, const CURRENT_RECONCILE& data) { } writer->EndArray(); - writer->String("list"); - writer->StartArray(); - for (auto & i : data.list_) { - saveToJson(writer, i); - } - writer->EndArray(); - writer->String("retry_step"); writer->Int(static_cast(data.retry_step_)); diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.h b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.h index 696883185ba1..952ffb2517ec 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.h @@ -230,11 +230,25 @@ struct PUBLISHER_ST { unsigned int status_ = 0; }; +struct RECONCILE_DIRECTION { + RECONCILE_DIRECTION(); + RECONCILE_DIRECTION(const std::string& publisher_key, + double amount_percent); + ~RECONCILE_DIRECTION(); + + bool loadFromJson(const std::string &json); + + std::string publisher_key_; + double amount_percent_; +}; + +typedef std::vector Directions; + struct WINNERS_ST { WINNERS_ST(); ~WINNERS_ST(); - PUBLISHER_ST publisher_data_; + RECONCILE_DIRECTION direction_; unsigned int votes_ = 0; }; @@ -261,21 +275,7 @@ struct SURVEYOR_ST { std::string surveySK_; }; -struct RECONCILE_DIRECTION { - RECONCILE_DIRECTION(); - RECONCILE_DIRECTION(const std::string& publisher_key, - int amount, - const std::string& currency); - ~RECONCILE_DIRECTION(); - - bool loadFromJson(const std::string &json); - std::string publisher_key_; - int amount_; - std::string currency_; -}; - -typedef std::vector Directions; typedef std::vector PublisherList; struct CURRENT_RECONCILE { @@ -299,7 +299,6 @@ struct CURRENT_RECONCILE { double fee_; Directions directions_; ledger::RewardsType type_; - PublisherList list_; ledger::ContributionRetry retry_step_; int retry_level_; std::string destination_; diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/common/bind_util.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/common/bind_util.cc new file mode 100644 index 000000000000..f1a2eec7e560 --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/common/bind_util.cc @@ -0,0 +1,95 @@ +/* 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/. */ + +#include +#include + +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "bat/ledger/internal/common/bind_util.h" + +namespace braveledger_bind_util { + +std::string FromContributionQueueToString(ledger::ContributionQueuePtr info) { + base::Value publishers(base::Value::Type::LIST); + for (auto& item : info->publishers) { + base::Value publisher(base::Value::Type::DICTIONARY); + publisher.SetStringKey("publisher_key", item->publisher_key); + publisher.SetStringKey("amount_percent", + std::to_string(item->amount_percent)); + publishers.GetList().push_back(std::move(publisher)); + } + + base::Value queue(base::Value::Type::DICTIONARY); + + queue.SetStringKey("id", std::to_string(info->id)); + queue.SetIntKey("type", static_cast(info->type)); + queue.SetStringKey("amount", std::to_string(info->amount)); + queue.SetBoolKey("partial", info->partial); + queue.SetKey("publishers", std::move(publishers)); + + std::string json; + base::JSONWriter::Write(queue, &json); + + return json; +} + +ledger::ContributionQueuePtr FromStringToContributionQueue( + const std::string& data) { + auto queue = ledger::ContributionQueue::New(); + base::Optional value = base::JSONReader::Read(data); + + if (!value || !value->is_dict()) { + return nullptr; + } + + base::DictionaryValue* dictionary = nullptr; + if (!value->GetAsDictionary(&dictionary)) { + return nullptr; + } + + auto* id = dictionary->FindKey("id"); + if (id && id->is_string()) { + queue->id = std::stoull(id->GetString()); + } + + auto* type = dictionary->FindKey("type"); + if (type && type->is_int()) { + queue->type = static_cast(type->GetInt()); + } + + auto* amount = dictionary->FindKey("amount"); + if (amount && amount->is_string()) { + queue->amount = std::stod(amount->GetString()); + } + + auto* partial = dictionary->FindKey("partial"); + if (partial && partial->is_bool()) { + queue->partial = partial->GetBool(); + } + + auto* publishers = dictionary->FindKey("publishers"); + if (publishers && publishers->is_list()) { + base::ListValue publishers_list(publishers->GetList()); + for (auto& item : publishers_list) { + auto publisher = ledger::ContributionQueuePublisher::New(); + auto* publisher_key = item.FindKey("publisher_key"); + if (!publisher_key || !publisher_key->is_string()) { + continue; + } + publisher->publisher_key = publisher_key->GetString(); + + auto* amount_percent = item.FindKey("amount_percent"); + if (amount_percent && amount_percent->is_string()) { + publisher->amount_percent = std::stod(amount_percent->GetString()); + } + queue->publishers.push_back(std::move(publisher)); + } + } + + return queue; +} + +} // namespace braveledger_bind_util diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/common/bind_util.h b/vendor/bat-native-ledger/src/bat/ledger/internal/common/bind_util.h new file mode 100644 index 000000000000..03c5b7c18d36 --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/common/bind_util.h @@ -0,0 +1,30 @@ +/* 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 BRAVELEDGER_COMMON_BIND_UTIL_H_ +#define BRAVELEDGER_COMMON_BIND_UTIL_H_ + +#include + +#include "bat/ledger/mojom_structs.h" + +/*** + * NOTICE!!! + * + * Add to this file ONLY conversion that you need when sending mojo object with + * bind and this only applies for nested mojo structs. If you have single level + * mojo struct std::bind works ok. + */ + +namespace braveledger_bind_util { + +std::string FromContributionQueueToString(ledger::ContributionQueuePtr info); + +ledger::ContributionQueuePtr FromStringToContributionQueue( + const std::string& data); + +} // namespace braveledger_bind_util + +#endif // BRAVELEDGER_COMMON_BIND_UTIL_H_ diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution.cc index e7ca04d8ace3..f43963907a57 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution.cc @@ -13,7 +13,9 @@ #include "base/time/time.h" #include "bat/ledger/global_constants.h" +#include "bat/ledger/internal/common/bind_util.h" #include "bat/ledger/internal/contribution/contribution.h" +#include "bat/ledger/internal/contribution/contribution_util.h" #include "bat/ledger/internal/contribution/phase_one.h" #include "bat/ledger/internal/contribution/phase_two.h" #include "bat/ledger/internal/contribution/unverified.h" @@ -36,7 +38,7 @@ Contribution::Contribution(bat_ledger::LedgerImpl* ledger) : unverified_(std::make_unique(ledger, this)), uphold_(std::make_unique(ledger)), last_reconcile_timer_id_(0u), - delay_ac_timer_id(0u) { + queue_timer_id_(0u) { } Contribution::~Contribution() { @@ -59,6 +61,34 @@ void Contribution::Initialize() { DoRetry(reconcile.viewingId_); } } + + // Process contribution queue + CheckContributionQueue(); +} + +void Contribution::CheckContributionQueue() { + const auto start_timer_in = ledger::is_testing + ? 1 + : brave_base::random::Geometric(15); + + SetTimer(&queue_timer_id_, start_timer_in); +} + +void Contribution::ProcessContributionQueue() { + const auto callback = std::bind(&Contribution::OnProcessContributionQueue, + this, + _1); + ledger_->GetFirstContributionQueue(callback); +} + +void Contribution::OnProcessContributionQueue( + ledger::ContributionQueuePtr info) { + if (!info) { + return; + } + + InitReconcile(std::move(info)); + CheckContributionQueue(); } void Contribution::HasSufficientBalance( @@ -121,8 +151,7 @@ double Contribution::GetTotalFromRecurringVerified( } ledger::PublisherInfoList Contribution::GetVerifiedListRecurring( - const ledger::PublisherInfoList& list, - double* budget) { + const ledger::PublisherInfoList& list) { ledger::PublisherInfoList verified; ledger::PendingContributionList non_verified; @@ -133,7 +162,6 @@ ledger::PublisherInfoList Contribution::GetVerifiedListRecurring( if (publisher->status != ledger::PublisherStatus::NOT_VERIFIED) { verified.push_back(publisher->Clone()); - *budget += publisher->weight; } else { auto contribution = ledger::PendingContribution::New(); contribution->amount = publisher->weight; @@ -154,66 +182,40 @@ ledger::PublisherInfoList Contribution::GetVerifiedListRecurring( return verified; } -void Contribution::PrepareACList( - ledger::PublisherInfoList list, - uint32_t next_record) { - ledger::PublisherInfoList normalized_list; - braveledger_bat_helper::PublisherList new_list; - - ledger_->NormalizeContributeWinners(&normalized_list, &list, 0); - for (const auto &publisher : normalized_list) { - if (publisher->percent == 0) { - continue; - } - - braveledger_bat_helper::PUBLISHER_ST new_publisher; - new_publisher.id_ = publisher->id; - new_publisher.percent_ = publisher->percent; - new_publisher.weight_ = publisher->weight; - new_publisher.duration_ = publisher->duration; - new_publisher.score_ = publisher->score; - new_publisher.visits_ = publisher->visits; - new_publisher.status_ = static_cast(publisher->status); - new_list.push_back(new_publisher); - } - - InitReconcile(ledger::RewardsType::AUTO_CONTRIBUTE, - new_list, - {}, - ledger_->GetContributionAmount()); +void Contribution::StartRecurringTips(ledger::ResultCallback callback) { + ledger_->GetRecurringTips( + std::bind(&Contribution::PrepareRecurringList, + this, + _1, + _2, + callback)); } void Contribution::PrepareRecurringList( ledger::PublisherInfoList list, - uint32_t next_record) { - double budget = 0.0; - - if (list.empty()) { - StartAutoContribute(); - return; - } else { - int delay = 30; - if (ledger::is_testing) { - delay = 1; - } - SetTimer(&delay_ac_timer_id, delay); - } - - auto verified_list = GetVerifiedListRecurring(list, &budget); - braveledger_bat_helper::Directions directions; - - for (const auto &publisher : verified_list) { - braveledger_bat_helper::RECONCILE_DIRECTION direction; - direction.publisher_key_ = publisher->id; - direction.amount_ = publisher->weight; - direction.currency_ = "BAT"; - directions.push_back(direction); + uint32_t next_record, + ledger::ResultCallback callback) { + auto verified_list = GetVerifiedListRecurring(list); + + for (const auto &item : verified_list) { + ledger::ContributionQueuePublisherList queue_list; + auto publisher = ledger::ContributionQueuePublisher::New(); + publisher->publisher_key = item->id; + publisher->amount_percent = 100.0; + queue_list.push_back(std::move(publisher)); + + auto queue = ledger::ContributionQueue::New(); + queue->type = ledger::RewardsType::RECURRING_TIP; + queue->amount = item->weight; + queue->partial = false; + queue->publishers = std::move(queue_list); + + ledger_->InsertOrUpdateContributionQueue( + std::move(queue), + [](const ledger::Result _){}); } - - InitReconcile(ledger::RewardsType::RECURRING_TIP, - {}, - directions, - budget); + CheckContributionQueue(); + callback(ledger::Result::LEDGER_OK); } void Contribution::ResetReconcileStamp() { @@ -222,17 +224,22 @@ void Contribution::ResetReconcileStamp() { } void Contribution::StartMonthlyContribution() { - BLOG(ledger_, ledger::LogLevel::LOG_INFO) << "Staring monthly contribution"; + BLOG(ledger_, ledger::LogLevel::LOG_INFO) << "Staring monthly contribution"; if (!ledger_->GetRewardsMainEnabled()) { ResetReconcileStamp(); return; } - ledger_->GetRecurringTips( - std::bind(&Contribution::PrepareRecurringList, - this, - _1, - _2)); + auto callback = std::bind(&Contribution::OnStartRecurringTips, + this, + _1); + + StartRecurringTips(callback); +} + +void Contribution::OnStartRecurringTips(const ledger::Result result) { + StartAutoContribute(ledger_->GetReconcileStamp()); + ResetReconcileStamp(); } bool Contribution::ShouldStartAutoContribute() { @@ -243,20 +250,15 @@ bool Contribution::ShouldStartAutoContribute() { return ledger_->GetAutoContribute(); } -void Contribution::StartAutoContribute() { - if (!ShouldStartAutoContribute()) { - ResetReconcileStamp(); - return; - } - - uint64_t current_reconcile_stamp = ledger_->GetReconcileStamp(); +void Contribution::StartAutoContribute(uint64_t reconcile_stamp) { auto filter = ledger_->CreateActivityFilter( "", ledger::ExcludeFilter::FILTER_ALL_EXCEPT_EXCLUDED, true, - current_reconcile_stamp, + reconcile_stamp, false, ledger_->GetPublisherMinVisits()); + ledger_->GetActivityInfoList( 0, 0, @@ -267,41 +269,66 @@ void Contribution::StartAutoContribute() { _2)); } +void Contribution::PrepareACList( + ledger::PublisherInfoList list, + uint32_t next_record) { + ledger::PublisherInfoList normalized_list; + + ledger_->NormalizeContributeWinners(&normalized_list, &list, 0); + + if (normalized_list.empty()) { + return; + } + + ledger::ContributionQueuePublisherList queue_list; + for (const auto &item : normalized_list) { + if (item->percent == 0) { + continue; + } + + auto publisher = ledger::ContributionQueuePublisher::New(); + publisher->publisher_key = item->id; + publisher->amount_percent = item->weight; + queue_list.push_back(std::move(publisher)); + } + + auto queue = ledger::ContributionQueue::New(); + queue->type = ledger::RewardsType::AUTO_CONTRIBUTE; + queue->amount = ledger_->GetContributionAmount(); + queue->partial = true; + queue->publishers = std::move(queue_list); + ledger_->InsertOrUpdateContributionQueue( + std::move(queue), + [](const ledger::Result _){}); + CheckContributionQueue(); +} + void Contribution::OnBalanceForReconcile( - const ledger::RewardsType type, - const braveledger_bat_helper::PublisherList& list, - const braveledger_bat_helper::Directions& directions, - double budget, + const std::string& contribution_queue, const ledger::Result result, ledger::BalancePtr info) { + auto const contribution = + braveledger_bind_util::FromStringToContributionQueue(contribution_queue); if (result != ledger::Result::LEDGER_OK || !info) { BLOG(ledger_, ledger::LogLevel::LOG_ERROR) << "We couldn't get balance from the server."; phase_one_->Complete(ledger::Result::LEDGER_ERROR, "", - type); + contribution->type); return; } - ProcessReconcile(type, - list, - directions, - budget, - std::move(info)); + ProcessReconcile(contribution->Clone(), std::move(info)); } -void Contribution::InitReconcile( - const ledger::RewardsType type, - const braveledger_bat_helper::PublisherList& list, - const braveledger_bat_helper::Directions& directions, - double budget) { + +void Contribution::InitReconcile(ledger::ContributionQueuePtr info) { + const auto info_converted = + braveledger_bind_util::FromContributionQueueToString(std::move(info)); ledger_->FetchBalance( std::bind(&Contribution::OnBalanceForReconcile, this, - type, - list, - directions, - budget, + info_converted, _1, _2)); } @@ -317,10 +344,8 @@ void Contribution::OnTimer(uint32_t timer_id) { return; } - if (timer_id == delay_ac_timer_id) { - delay_ac_timer_id = 0; - StartAutoContribute(); - return; + if (timer_id == queue_timer_id_) { + ProcessContributionQueue(); } for (std::pair const& value : retry_timers_) { @@ -367,21 +392,24 @@ void Contribution::OnReconcileCompleteSuccess( int year, uint32_t date) { if (type == ledger::RewardsType::AUTO_CONTRIBUTE) { - ledger_->SetBalanceReportItem(month, - year, - ledger::ReportType::AUTO_CONTRIBUTION, - probi); + ledger_->SetBalanceReportItem( + month, + year, + GetReportTypeFromRewardsType(type), + probi); ledger_->SaveContributionInfo(probi, month, year, date, "", type); return; } - if (type == ledger::RewardsType::ONE_TIME_TIP) { - ledger_->SetBalanceReportItem(month, - year, - ledger::ReportType::TIP, - probi); - auto reconcile = ledger_->GetReconcileById(viewing_id); - auto donations = reconcile.directions_; + if (type == ledger::RewardsType::ONE_TIME_TIP || + type == ledger::RewardsType::RECURRING_TIP) { + ledger_->SetBalanceReportItem( + month, + year, + GetReportTypeFromRewardsType(type), + probi); + const auto reconcile = ledger_->GetReconcileById(viewing_id); + const auto donations = reconcile.directions_; if (donations.size() > 0) { std::string publisher_key = donations[0].publisher_key_; ledger_->SaveContributionInfo(probi, @@ -393,27 +421,6 @@ void Contribution::OnReconcileCompleteSuccess( } return; } - - if (type == ledger::RewardsType::RECURRING_TIP) { - auto reconcile = ledger_->GetReconcileById(viewing_id); - ledger_->SetBalanceReportItem(month, - year, - ledger::ReportType::TIP_RECURRING, - probi); - for (auto &publisher : reconcile.list_) { - // TODO(nejczdovc) remove when we completely switch to probi - const std::string probi = - std::to_string(static_cast(publisher.weight_)) + - "000000000000000000"; - ledger_->SaveContributionInfo(probi, - month, - year, - date, - publisher.id_, - type); - } - return; - } } void Contribution::AddRetry( @@ -646,157 +653,103 @@ void Contribution::OnDoDirectTipServerPublisher( return; } - const auto direction = braveledger_bat_helper::RECONCILE_DIRECTION( - publisher_key, - amount, - currency); - const auto direction_list = - std::vector { direction }; - InitReconcile( - ledger::RewardsType::ONE_TIME_TIP, - {}, - direction_list); + ledger::ContributionQueuePublisherList queue_list; + auto publisher = ledger::ContributionQueuePublisher::New(); + publisher->publisher_key = publisher_key; + publisher->amount_percent = 100.0; + queue_list.push_back(std::move(publisher)); + + auto queue = ledger::ContributionQueue::New(); + queue->type = ledger::RewardsType::ONE_TIME_TIP; + queue->amount = amount; + queue->partial = false; + queue->publishers = std::move(queue_list); + + InitReconcile(std::move(queue)); callback(ledger::Result::LEDGER_OK); } bool Contribution::HaveReconcileEnoughFunds( - const ledger::RewardsType type, + ledger::ContributionQueuePtr contribution, double* fee, - double budget, - const double balance, - const braveledger_bat_helper::Directions& directions) { - if (type == ledger::RewardsType::AUTO_CONTRIBUTE) { + const double balance) { + if (contribution->type == ledger::RewardsType::AUTO_CONTRIBUTE) { if (balance == 0) { BLOG(ledger_, ledger::LogLevel::LOG_WARNING) << "You do not have enough funds for auto contribution"; phase_one_->Complete(ledger::Result::NOT_ENOUGH_FUNDS, "", - type); + contribution->type); return false; } - if (budget > balance) { - budget = balance; + if (contribution->amount > balance) { + contribution->amount = balance; } - *fee = budget; + *fee = contribution->amount; return true; } - if (type == ledger::RewardsType::RECURRING_TIP) { - if (budget > balance) { - BLOG(ledger_, ledger::LogLevel::LOG_WARNING) << - "You do not have enough funds to do monthly contribution"; - phase_one_->Complete(ledger::Result::NOT_ENOUGH_FUNDS, - "", - ledger::RewardsType::AUTO_CONTRIBUTE); - return false; - } - - *fee = budget; - return true; - } - - if (type == ledger::RewardsType::ONE_TIME_TIP) { - for (const auto& direction : directions) { - if (direction.publisher_key_.empty()) { - BLOG(ledger_, ledger::LogLevel::LOG_ERROR) << - "Reconcile direction missing publisher"; - phase_one_->Complete(ledger::Result::TIP_ERROR, - "", - type); - return false; - } - - if (direction.currency_ != LEDGER_CURRENCY || direction.amount_ == 0) { - BLOG(ledger_, ledger::LogLevel::LOG_ERROR) << - "Reconcile direction currency invalid for " << - direction.publisher_key_; - phase_one_->Complete(ledger::Result::TIP_ERROR, - "", - type); - return false; - } - - *fee += direction.amount_; - } - - if (*fee > balance) { - BLOG(ledger_, ledger::LogLevel::LOG_WARNING) << - "You do not have enough funds to do a tip"; - phase_one_->Complete(ledger::Result::NOT_ENOUGH_FUNDS, - "", - type); - return false; - } - - return true; + if (contribution->amount > balance) { + BLOG(ledger_, ledger::LogLevel::LOG_WARNING) << + "You do not have enough funds to do a contribution"; + phase_one_->Complete(ledger::Result::NOT_ENOUGH_FUNDS, + "", + contribution->type); + return false; } - return false; + *fee = contribution->amount; + return true; } -bool Contribution::IsListEmpty( - const ledger::RewardsType type, - const braveledger_bat_helper::PublisherList& list, - const braveledger_bat_helper::Directions& directions, - double budget) { - if (type == ledger::RewardsType::AUTO_CONTRIBUTE) { - if (list.size() == 0 || budget == 0) { - BLOG(ledger_, ledger::LogLevel::LOG_INFO) << - "Auto contribution table is empty"; - phase_one_->Complete(ledger::Result::AC_TABLE_EMPTY, - "", - type); - return true; - } - } - - if (type == ledger::RewardsType::RECURRING_TIP) { - if (directions.size() == 0 || budget == 0) { - phase_one_->Complete(ledger::Result::RECURRING_TABLE_EMPTY, - "", - ledger::RewardsType::RECURRING_TIP); - BLOG(ledger_, ledger::LogLevel::LOG_INFO) << - "Recurring tips list is empty"; - return true; - } +void Contribution::DeleteContributionQueue( + ledger::ContributionQueuePtr contribution) { + if (!contribution || contribution->id == 0) { + return; } - return false; + ledger_->DeleteContributionQueue( + contribution->id, + [](const ledger::Result _){}); } void Contribution::ProcessReconcile( - const ledger::RewardsType type, - const braveledger_bat_helper::PublisherList& list, - const braveledger_bat_helper::Directions& directions, - double budget, + ledger::ContributionQueuePtr contribution, ledger::BalancePtr info) { double fee = .0; - const auto have_enough_balance = HaveReconcileEnoughFunds(type, - &fee, - budget, - info->total, - directions); + const auto have_enough_balance = HaveReconcileEnoughFunds( + contribution->Clone(), + &fee, + info->total); + if (!have_enough_balance) { + DeleteContributionQueue(contribution->Clone()); return; } - if (IsListEmpty(type, list, directions, budget)) { + if (contribution->amount == 0 || contribution->publishers.empty()) { + DeleteContributionQueue(contribution->Clone()); return; } + const auto directions = FromContributionQueuePublishersToReconcileDirections( + std::move(contribution->publishers)); + auto anon_reconcile = braveledger_bat_helper::CURRENT_RECONCILE(); anon_reconcile.viewingId_ = ledger_->GenerateGUID(); anon_reconcile.fee_ = fee; + // TODO(tmancey): Temp conversion as we are moving everything into DB + // so this can be remove at that point anon_reconcile.directions_ = directions; - anon_reconcile.type_ = type; - anon_reconcile.list_ = list; + anon_reconcile.type_ = contribution->type; if (ledger_->ReconcileExists(anon_reconcile.viewingId_)) { BLOG(ledger_, ledger::LogLevel::LOG_ERROR) << "Unable to reconcile with the same viewing id: " << anon_reconcile.viewingId_; + DeleteContributionQueue(contribution->Clone()); return; } @@ -806,6 +759,7 @@ void Contribution::ProcessReconcile( info->wallets); if (anon_balance >= fee) { ledger_->AddReconcile(anon_reconcile.viewingId_, anon_reconcile); + DeleteContributionQueue(contribution->Clone()); phase_one_->Start(anon_reconcile.viewingId_); return; } @@ -817,8 +771,8 @@ void Contribution::ProcessReconcile( fee = fee - anon_balance; anon_reconcile.fee_ = anon_balance; - if (type == ledger::RewardsType::RECURRING_TIP || - type == ledger::RewardsType::ONE_TIME_TIP) { + if (contribution->type == ledger::RewardsType::RECURRING_TIP || + contribution->type == ledger::RewardsType::ONE_TIME_TIP) { braveledger_bat_helper::Directions anon_directions; AdjustTipsAmounts(directions, &wallet_directions, @@ -837,8 +791,7 @@ void Contribution::ProcessReconcile( wallet_reconcile.viewingId_ = ledger_->GenerateGUID(); wallet_reconcile.fee_ = fee; wallet_reconcile.directions_ = wallet_directions; - wallet_reconcile.type_ = type; - wallet_reconcile.list_ = list; + wallet_reconcile.type_ = contribution->type; ledger_->AddReconcile(wallet_reconcile.viewingId_, wallet_reconcile); auto tokens_callback = std::bind(&Contribution::OnExternalWallets, @@ -849,6 +802,7 @@ void Contribution::ProcessReconcile( // Check if we have token ledger_->GetExternalWallets(tokens_callback); + DeleteContributionQueue(contribution->Clone()); } void Contribution::AdjustTipsAmounts( @@ -862,20 +816,20 @@ void Contribution::AdjustTipsAmounts( continue; } - if (item.amount_ <= reduce_fee_for) { + if (item.amount_percent_ <= reduce_fee_for) { anon_directions->push_back(item); - reduce_fee_for -= item.amount_; + reduce_fee_for -= item.amount_percent_; continue; } - if (item.amount_ > reduce_fee_for) { + if (item.amount_percent_ > reduce_fee_for) { // anon wallet - const auto original_weight = item.amount_; - item.amount_ = reduce_fee_for; + const auto original_weight = item.amount_percent_; + item.amount_percent_ = reduce_fee_for; anon_directions->push_back(item); // rest to normal wallet - item.amount_ = original_weight - reduce_fee_for; + item.amount_percent_ = original_weight - reduce_fee_for; wallet_directions->push_back(item); reduce_fee_for = 0; @@ -926,12 +880,13 @@ void Contribution::OnExternalWallets( } for (const auto& item : reconcile.directions_) { + const auto amount = (item.amount_percent_ * reconcile.fee_) / 100; auto callback = std::bind(&Contribution::OnExternalWalletServerPublisherInfo, this, _1, viewing_id, - item.amount_, + static_cast(amount), *wallet); ledger_->GetServerPublisherInfo(item.publisher_key_, callback); diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution.h b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution.h index 0e4110cf6c95..a56bbb37e396 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution.h @@ -134,11 +134,7 @@ class Contribution { // Initial point for contribution // In this step we get balance from the server - void InitReconcile( - const ledger::RewardsType type, - const braveledger_bat_helper::PublisherList& list, - const braveledger_bat_helper::Directions& directions = {}, - double budget = 0); + void InitReconcile(ledger::ContributionQueuePtr info); // Called when timer is triggered void OnTimer(uint32_t timer_id); @@ -176,7 +172,7 @@ class Contribution { void ResetReconcileStamp(); // Triggers contribution process for auto contribute table - void StartAutoContribute(); + void StartAutoContribute(uint64_t reconcile_stamp); void ContributeUnverifiedPublishers(); @@ -189,23 +185,31 @@ class Contribution { ledger::DoDirectTipCallback callback); private: + void CheckContributionQueue(); + + void ProcessContributionQueue(); + + void OnProcessContributionQueue(ledger::ContributionQueuePtr info); + // RECURRING TIPS: from the list gets only verified publishers and // save unverified to the db ledger::PublisherInfoList GetVerifiedListRecurring( - const ledger::PublisherInfoList& all, - double* budget); + const ledger::PublisherInfoList& all); void PrepareACList(ledger::PublisherInfoList list, uint32_t next_record); - void PrepareRecurringList(ledger::PublisherInfoList list, - uint32_t next_record); + void StartRecurringTips(ledger::ResultCallback callback); + + void PrepareRecurringList( + ledger::PublisherInfoList list, + uint32_t next_record, + ledger::ResultCallback callback); + + void OnStartRecurringTips(const ledger::Result result); void OnBalanceForReconcile( - const ledger::RewardsType type, - const braveledger_bat_helper::PublisherList& list, - const braveledger_bat_helper::Directions& directions, - double budget, + const std::string& contribution_queue, const ledger::Result result, ledger::BalancePtr info); @@ -245,25 +249,16 @@ class Contribution { ledger::DoDirectTipCallback callback); bool HaveReconcileEnoughFunds( - const ledger::RewardsType type, + ledger::ContributionQueuePtr contribution, double* fee, - double budget, - const double balance, - const braveledger_bat_helper::Directions& directions); - - bool IsListEmpty( - const ledger::RewardsType type, - const braveledger_bat_helper::PublisherList& list, - const braveledger_bat_helper::Directions& directions, - double budget); + const double balance); void ProcessReconcile( - const ledger::RewardsType type, - const braveledger_bat_helper::PublisherList& list, - const braveledger_bat_helper::Directions& directions, - double budget, + ledger::ContributionQueuePtr contribution, ledger::BalancePtr info); + void DeleteContributionQueue(ledger::ContributionQueuePtr contribution); + void AdjustTipsAmounts( braveledger_bat_helper::Directions directions, braveledger_bat_helper::Directions* wallet_directions, @@ -292,7 +287,7 @@ class Contribution { std::unique_ptr uphold_; uint32_t last_reconcile_timer_id_; std::map retry_timers_; - uint32_t delay_ac_timer_id; + uint32_t queue_timer_id_; // For testing purposes friend class ContributionTest; diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution_util.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution_util.cc new file mode 100644 index 000000000000..3850dfcb3a0f --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution_util.cc @@ -0,0 +1,52 @@ +/* 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/. */ + +#include + +#include "bat/ledger/internal/contribution/contribution_util.h" + +namespace braveledger_contribution { + +braveledger_bat_helper::Directions +FromContributionQueuePublishersToReconcileDirections( + ledger::ContributionQueuePublisherList list) { + braveledger_bat_helper::Directions directions; + + for (auto& item : list) { + if (!item || item->publisher_key.empty()) { + continue; + } + + const auto direction = braveledger_bat_helper::RECONCILE_DIRECTION( + item->publisher_key, + item->amount_percent); + + directions.push_back(direction); + } + + return directions; +} + +ledger::ReportType GetReportTypeFromRewardsType( + const ledger::RewardsType type) { + switch (static_cast(type)) { + case static_cast(ledger::RewardsType::AUTO_CONTRIBUTE): { + return ledger::ReportType::AUTO_CONTRIBUTION; + } + case static_cast(ledger::RewardsType::ONE_TIME_TIP): { + return ledger::ReportType::TIP; + } + case static_cast(ledger::RewardsType::RECURRING_TIP): { + return ledger::ReportType::TIP_RECURRING; + } + default: { + // missing conversion, returning dummy value. + NOTREACHED(); + return ledger::ReportType::TIP; + } + } +} + +} // namespace braveledger_contribution diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution_util.h b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution_util.h new file mode 100644 index 000000000000..0b5faa0e078f --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/contribution_util.h @@ -0,0 +1,25 @@ +/* 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 BRAVELEDGER_CONTRIBUTION_CONTRIBUTION_UTIL_H_ +#define BRAVELEDGER_CONTRIBUTION_CONTRIBUTION_UTIL_H_ + +#include +#include + +#include "bat/ledger/mojom_structs.h" +#include "bat/ledger/internal/bat_helper.h" + +namespace braveledger_contribution { + +braveledger_bat_helper::Directions +FromContributionQueuePublishersToReconcileDirections( + ledger::ContributionQueuePublisherList list); + +ledger::ReportType GetReportTypeFromRewardsType(const ledger::RewardsType type); + +} // namespace braveledger_contribution + +#endif // BRAVELEDGER_CONTRIBUTION_CONTRIBUTION_UTIL_H_ diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_one.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_one.cc index 5e85e5ace6ae..79aba9ca801b 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_one.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_one.cc @@ -499,11 +499,6 @@ void PhaseOne::Complete(ledger::Result result, const std::string& viewing_id, const ledger::RewardsType type, const std::string& probi) { - // Set timer to the next month when AC is complete - if (type == ledger::RewardsType::AUTO_CONTRIBUTE) { - contribution_->ResetReconcileStamp(); - } - ledger_->OnReconcileComplete(result, viewing_id, probi, type); if (result != ledger::Result::LEDGER_OK) { diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two.cc index a2689e423ecc..956a262b3ae6 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two.cc @@ -23,12 +23,6 @@ using std::placeholders::_3; namespace braveledger_contribution { -static bool winners_votes_compare( - const braveledger_bat_helper::WINNERS_ST& first, - const braveledger_bat_helper::WINNERS_ST& second) { - return (first.votes_ < second.votes_); -} - PhaseTwo::PhaseTwo(bat_ledger::LedgerImpl* ledger, Contribution* contribution) : ledger_(ledger), @@ -51,25 +45,17 @@ void PhaseTwo::Start(const std::string& viewing_id) { switch (reconcile.type_) { case ledger::RewardsType::AUTO_CONTRIBUTE: { - GetContributeWinners(ballots_count, viewing_id, reconcile.list_); - break; - } - - case ledger::RewardsType::RECURRING_TIP: { - GetTipsWinners(ballots_count, viewing_id); + GetContributeWinners(ballots_count, viewing_id, reconcile.directions_); break; } + case ledger::RewardsType::RECURRING_TIP: case ledger::RewardsType::ONE_TIME_TIP: { - // Direct one-time contribution braveledger_bat_helper::WINNERS_ST winner; winner.votes_ = ballots_count; - winner.publisher_data_.id_ = reconcile.directions_.front().publisher_key_; - winner.publisher_data_.duration_ = 0; - winner.publisher_data_.score_ = 0; - winner.publisher_data_.visits_ = 0; - winner.publisher_data_.percent_ = 0; - winner.publisher_data_.weight_ = 0; + winner.direction_.publisher_key_ = + reconcile.directions_.front().publisher_key_; + winner.direction_.amount_percent_ = 100.0; VotePublishers(braveledger_bat_helper::Winners { winner }, viewing_id); break; } @@ -97,16 +83,16 @@ unsigned int PhaseTwo::GetBallotsCount( bool PhaseTwo::GetStatisticalVotingWinner( double dart, - const braveledger_bat_helper::PublisherList& list, + const braveledger_bat_helper::Directions& directions, braveledger_bat_helper::WINNERS_ST* winner) { double upper = 0.0; - for (const auto& item : list) { - upper += item.weight_ / 100.0; + for (const auto& item : directions) { + upper += item.amount_percent_ / 100.0; if (upper < dart) continue; winner->votes_ = 1; - winner->publisher_data_ = item; + winner->direction_ = item; return true; } @@ -116,13 +102,13 @@ bool PhaseTwo::GetStatisticalVotingWinner( braveledger_bat_helper::Winners PhaseTwo::GetStatisticalVotingWinners( uint32_t total_votes, - const braveledger_bat_helper::PublisherList& list) { + const braveledger_bat_helper::Directions& directions) { braveledger_bat_helper::Winners winners; while (total_votes > 0) { double dart = brave_base::random::Uniform_01(); braveledger_bat_helper::WINNERS_ST winner; - if (GetStatisticalVotingWinner(dart, list, &winner)) { + if (GetStatisticalVotingWinner(dart, directions, &winner)) { winners.push_back(winner); --total_votes; } @@ -134,59 +120,19 @@ braveledger_bat_helper::Winners PhaseTwo::GetStatisticalVotingWinners( void PhaseTwo::GetContributeWinners( const unsigned int ballots, const std::string& viewing_id, - const braveledger_bat_helper::PublisherList& list) { + const braveledger_bat_helper::Directions& directions) { braveledger_bat_helper::Winners winners = - GetStatisticalVotingWinners(ballots, list); + GetStatisticalVotingWinners(ballots, directions); VotePublishers(winners, viewing_id); } -void PhaseTwo::GetTipsWinners( - const unsigned int ballots, - const std::string& viewing_id) { - const auto reconcile = ledger_->GetReconcileById(viewing_id); - unsigned int total_votes = 0; - braveledger_bat_helper::Winners res; - - for (const auto &item : reconcile.directions_) { - if (item.amount_ <= 0) { - continue; - } - - braveledger_bat_helper::WINNERS_ST winner; - double percent = item.amount_ / reconcile.fee_; - winner.votes_ = static_cast(std::lround(percent * - static_cast(ballots))); - total_votes += winner.votes_; - winner.publisher_data_.id_ = item.publisher_key_; - winner.publisher_data_.duration_ = 0; - winner.publisher_data_.score_ = 0; - winner.publisher_data_.visits_ = 0; - winner.publisher_data_.percent_ = 0; - winner.publisher_data_.weight_ = 0; - res.push_back(winner); - } - - if (res.size()) { - while (total_votes > ballots) { - braveledger_bat_helper::Winners::iterator max = - std::max_element(res.begin(), res.end(), winners_votes_compare); - (max->votes_)--; - total_votes--; - } - } else { - // TODO(nejczdovc) what should we do in this case? - } - - VotePublishers(res, viewing_id); -} - void PhaseTwo::VotePublishers( const braveledger_bat_helper::Winners& winners, const std::string& viewing_id) { std::vector publishers; for (size_t i = 0; i < winners.size(); i++) { for (size_t j = 0; j < winners[i].votes_; j++) { - publishers.push_back(winners[i].publisher_data_.id_); + publishers.push_back(winners[i].direction_.publisher_key_); } } diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two.h b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two.h index d94d7f1b3e40..be50f9ab08d5 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two.h @@ -47,16 +47,17 @@ class PhaseTwo { bool GetStatisticalVotingWinner( double dart, - const braveledger_bat_helper::PublisherList& list, + const braveledger_bat_helper::Directions& list, braveledger_bat_helper::WINNERS_ST* winner); braveledger_bat_helper::Winners GetStatisticalVotingWinners( uint32_t total_votes, - const braveledger_bat_helper::PublisherList& list); + const braveledger_bat_helper::Directions& list); - void GetContributeWinners(const unsigned int ballots, - const std::string& viewing_id, - const braveledger_bat_helper::PublisherList& list); + void GetContributeWinners( + const unsigned int ballots, + const std::string& viewing_id, + const braveledger_bat_helper::Directions& list); void GetTipsWinners(const unsigned int ballots, const std::string& viewing_id); diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two_unittest.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two_unittest.cc index 056ad46b1702..8eed72ddbb56 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two_unittest.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/phase_two_unittest.cc @@ -19,27 +19,27 @@ namespace braveledger_contribution { class PhaseTwoTest : public testing::Test { protected: - void PopulatePublisherList(braveledger_bat_helper::PublisherList* list) { - braveledger_bat_helper::PUBLISHER_ST publisher; + void PopulateDirectionsList(braveledger_bat_helper::Directions* list) { + braveledger_bat_helper::RECONCILE_DIRECTION publisher; - publisher.id_ = "publisher1"; - publisher.weight_ = 2.0; + publisher.publisher_key_ = "publisher1"; + publisher.amount_percent_ = 2.0; list->push_back(publisher); - publisher.id_ = "publisher2"; - publisher.weight_ = 13.0; + publisher.publisher_key_ = "publisher2"; + publisher.amount_percent_ = 13.0; list->push_back(publisher); - publisher.id_ = "publisher3"; - publisher.weight_ = 14.0; + publisher.publisher_key_ = "publisher3"; + publisher.amount_percent_ = 14.0; list->push_back(publisher); - publisher.id_ = "publisher4"; - publisher.weight_ = 23.0; + publisher.publisher_key_ = "publisher4"; + publisher.amount_percent_ = 23.0; list->push_back(publisher); - publisher.id_ = "publisher5"; - publisher.weight_ = 38.0; + publisher.publisher_key_ = "publisher5"; + publisher.amount_percent_ = 38.0; list->push_back(publisher); } }; @@ -48,8 +48,8 @@ TEST_F(PhaseTwoTest, GetStatisticalVotingWinners) { auto phase_two = std::make_unique(nullptr, nullptr); - braveledger_bat_helper::PublisherList publisher_list; - PopulatePublisherList(&publisher_list); + braveledger_bat_helper::Directions list; + PopulateDirectionsList(&list); struct { double dart; @@ -71,9 +71,9 @@ TEST_F(PhaseTwoTest, GetStatisticalVotingWinners) { for (size_t i = 0; i < base::size(cases); i++) { braveledger_bat_helper::WINNERS_ST winner; bool result = phase_two->GetStatisticalVotingWinner( - cases[i].dart, publisher_list, &winner); + cases[i].dart, list, &winner); EXPECT_TRUE(result); - EXPECT_STREQ(winner.publisher_data_.id_.c_str(), cases[i].publisher); + EXPECT_STREQ(winner.direction_.publisher_key_.c_str(), cases[i].publisher); } } diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/unverified.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/unverified.cc index 3922455d6b0c..1919eb7e1ea7 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/unverified.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/contribution/unverified.cc @@ -3,6 +3,8 @@ * 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 + #include "bat/ledger/internal/contribution/unverified.h" #include "bat/ledger/internal/ledger_impl.h" @@ -98,17 +100,19 @@ void Unverified::OnContributeUnverifiedPublishers( // Trigger contribution if (balance >= current->amount) { - auto direction = braveledger_bat_helper::RECONCILE_DIRECTION( - current->publisher_key, - current->amount, - "BAT"); - - auto direction_list = std::vector - { direction }; - contribution_->InitReconcile( - ledger::RewardsType::ONE_TIME_TIP, - {}, - direction_list); + ledger::ContributionQueuePublisherList queue_list; + auto publisher = ledger::ContributionQueuePublisher::New(); + publisher->publisher_key = current->publisher_key; + publisher->amount_percent = 100.0; + queue_list.push_back(std::move(publisher)); + + auto queue = ledger::ContributionQueue::New(); + queue->type = ledger::RewardsType::ONE_TIME_TIP; + queue->amount = current->amount; + queue->partial = false; + queue->publishers = std::move(queue_list); + + contribution_->InitReconcile(std::move(queue)); ledger_->RemovePendingContribution( current->publisher_key, diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc index a1b04d352d43..7f78d5f53fc5 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc @@ -1589,4 +1589,21 @@ void LedgerImpl::ApplySafetynetToken( bat_grants_->SetGrant("", promotion_id, token); } +void LedgerImpl::InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + ledger::ResultCallback callback) { + ledger_client_->InsertOrUpdateContributionQueue(std::move(info), callback); +} + +void LedgerImpl::DeleteContributionQueue( + const uint64_t id, + ledger::ResultCallback callback) { + ledger_client_->DeleteContributionQueue(id, callback); +} + +void LedgerImpl::GetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback) { + ledger_client_->GetFirstContributionQueue(callback); +} + } // namespace bat_ledger diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.h b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.h index 1a9587b2a45e..e0cdcc68473f 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.h @@ -578,6 +578,17 @@ class LedgerImpl : public ledger::Ledger, const std::string& wallet_type, const std::string& id); + void InsertOrUpdateContributionQueue( + ledger::ContributionQueuePtr info, + ledger::ResultCallback callback); + + void DeleteContributionQueue( + const uint64_t id, + ledger::ResultCallback callback); + + void GetFirstContributionQueue( + ledger::GetFirstContributionQueueCallback callback); + private: void OnLoad(ledger::VisitDataPtr visit_data, const uint64_t& current_time) override; diff --git a/vendor/brave-ios/BUILD.gn b/vendor/brave-ios/BUILD.gn index c4362768f996..e2c8d7859559 100644 --- a/vendor/brave-ios/BUILD.gn +++ b/vendor/brave-ios/BUILD.gn @@ -123,6 +123,10 @@ ios_framework_bundle("brave_rewards_ios_framework") { "Ledger/Data/Model/ServerPublisherBanner.m", "Ledger/Data/Model/ServerPublisherLink.h", "Ledger/Data/Model/ServerPublisherLink.m", + "Ledger/Data/Model/ContributionQueue.h", + "Ledger/Data/Model/ContributionQueue.m", + "Ledger/Data/Model/ContributionPublisher.h", + "Ledger/Data/Model/ContributionPublisher.m", "$target_gen_dir/ledger.mojom.objc.h", "$target_gen_dir/ledger.mojom.objc+private.h", "$target_gen_dir/ledger.mojom.objc.mm", diff --git a/vendor/brave-ios/Ledger/BATBraveLedger.mm b/vendor/brave-ios/Ledger/BATBraveLedger.mm index 80ed9fe2a309..d00fddbfcefd 100644 --- a/vendor/brave-ios/Ledger/BATBraveLedger.mm +++ b/vendor/brave-ios/Ledger/BATBraveLedger.mm @@ -47,6 +47,8 @@ + (void)__objc_setter:(__type)newValue { ledger::__cpp_var = newValue; } static NSString * const kUserHasFundedKey = @"BATRewardsUserHasFunded"; static NSString * const kBackupSucceededKey = @"BATRewardsBackupSucceeded"; +static NSString * const kContributionQueueAutoincrementID = @"BATContributionQueueAutoincrementID"; + static const auto kOneDay = base::Time::kHoursPerDay * base::Time::kSecondsPerHour; /// Ledger Prefs, keys will be defined in `bat/ledger/option_keys.h` @@ -1858,4 +1860,35 @@ - (void)removeTransferFee:(const std::string &)wallet_type id:(const std::string // FIXME: Add implementation } +- (void)insertOrUpdateContributionQueue:(ledger::ContributionQueuePtr)info callback:(ledger::ResultCallback)callback +{ + if (info.get() == nullptr) { return; } + + if (info->id == 0) { + NSNumber *nextID = self.prefs[kContributionQueueAutoincrementID] ?: [NSNumber numberWithUnsignedLongLong:1]; + info->id = [nextID unsignedLongLongValue]; + self.prefs[kContributionQueueAutoincrementID] = @([nextID unsignedLongLongValue] + 1); + [self savePrefs]; + } + + const auto queue = [[BATContributionQueue alloc] initWithContributionQueue:*info]; + [BATLedgerDatabase insertOrUpdateContributionQueue:queue completion:^(BOOL success) { + callback(success ? ledger::Result::LEDGER_OK : ledger::Result::LEDGER_ERROR); + }]; +} + +- (void)deleteContributionQueue:(const uint64_t) id callback:(ledger::ResultCallback)callback +{ + [BATLedgerDatabase deleteQueueWithID:id completion:^(BOOL success) { + callback(success ? ledger::Result::LEDGER_OK : ledger::Result::LEDGER_ERROR); + }]; +} + +- (void)getFirstContributionQueue:(ledger::GetFirstContributionQueueCallback)callback +{ + const auto queue = [BATLedgerDatabase firstQueue]; + callback(queue != nil ? queue.cppObjPtr : nullptr); +} + + @end diff --git a/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.h b/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.h index b1948c436881..3c15b0f003ea 100644 --- a/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.h +++ b/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.h @@ -52,6 +52,16 @@ typedef void (^BATLedgerDatabaseWriteCompletion)(BOOL success); + (NSArray *)oneTimeTipsPublishersForMonth:(BATActivityMonth)month year:(int)year; +#pragma mark - Contribution Queue + ++ (void)insertOrUpdateContributionQueue:(BATContributionQueue *)queue + completion:(nullable BATLedgerDatabaseWriteCompletion)completion; + ++ (nullable BATContributionQueue *)firstQueue; + ++ (void)deleteQueueWithID:(int64_t)queueID + completion:(nullable BATLedgerDatabaseWriteCompletion)completion; + #pragma mark - Activity Info /// Insert or update activity info from a publisher diff --git a/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.mm b/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.mm index 0da8ce61f790..ffad1e397622 100644 --- a/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.mm +++ b/vendor/brave-ios/Ledger/Data/BATLedgerDatabase.mm @@ -27,15 +27,31 @@ @implementation BATLedgerDatabase + (nullable __kindof NSManagedObject *)firstOfClass:(Class)clazz - withPublisherID:(NSString *)publisherID - additionalPredicate:(nullable NSPredicate *)additionalPredicate + predicates:(NSArray *)predicates + sortDescriptors:(NSArray *)sortDescriptors context:(NSManagedObjectContext *)context { const auto fetchRequest = [clazz fetchRequest]; fetchRequest.entity = [NSEntityDescription entityForName:NSStringFromClass(clazz) inManagedObjectContext:context]; fetchRequest.fetchLimit = 1; + fetchRequest.sortDescriptors = sortDescriptors; + fetchRequest.predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; + + NSError *error; + const auto fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; + if (error) { + NSLog(@"%s: %@", __PRETTY_FUNCTION__, error); + } + + return fetchedObjects.firstObject; +} ++ (nullable __kindof NSManagedObject *)firstOfClass:(Class)clazz + withPublisherID:(NSString *)publisherID + additionalPredicate:(nullable NSPredicate *)additionalPredicate + context:(NSManagedObjectContext *)context +{ const auto predicates = [[NSMutableArray alloc] init]; [predicates addObject:[NSPredicate predicateWithFormat:@"publisherID == %@", publisherID]]; @@ -43,15 +59,7 @@ + (nullable __kindof NSManagedObject *)firstOfClass:(Class)clazz [predicates addObject:additionalPredicate]; } - fetchRequest.predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; - - NSError *error; - const auto fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; - if (error) { - NSLog(@"%s: %@", __PRETTY_FUNCTION__, error); - } - - return fetchedObjects.firstObject; + return [self firstOfClass:clazz predicates:predicates sortDescriptors:@[] context:context]; } + (nullable PublisherInfo *)getPublisherInfoWithID:(NSString *)publisherID context:(NSManagedObjectContext *)context @@ -286,6 +294,92 @@ + (void)insertContributionInfo:(NSString *)probi month:(const BATActivityMonth)m return publishers; } +#pragma mark - Contribution Queue + ++ (nullable ContributionQueue *)getContributionQueueWithID:(int64_t)queueID context:(NSManagedObjectContext *)context +{ + const auto predicate = [NSPredicate predicateWithFormat:@"id == %ld", queueID]; + return [self firstOfClass:ContributionQueue.class predicates:@[predicate] sortDescriptors:@[] context:context]; +} + ++ (nullable ContributionPublisher *)getContributionPublisherWithQueueID:(int64_t)queueID context:(NSManagedObjectContext *)context +{ + const auto predicate = [NSPredicate predicateWithFormat:@"queue.id == %ld", queueID]; + return [self firstOfClass:ContributionPublisher.class predicates:@[predicate] sortDescriptors:@[] context:context]; +} + ++ (void)insertOrUpdateContributionQueue:(BATContributionQueue *)queue + completion:(nullable BATLedgerDatabaseWriteCompletion)completion +{ + [DataController.shared performOnContext:nil task:^(NSManagedObjectContext * _Nonnull context) { + const auto cq = [self getContributionQueueWithID:queue.id context:context] ?: + [[ContributionQueue alloc] initWithEntity:[NSEntityDescription entityForName:NSStringFromClass(ContributionQueue.class) inManagedObjectContext:context] + insertIntoManagedObjectContext:context]; + cq.id = queue.id; + cq.type = static_cast(queue.type); + cq.amount = queue.amount; + cq.partial = queue.partial; + [self insertContributionPublishersIntoQueue:cq publishers:queue.publishers context:context]; + } completion:WriteToDataControllerCompletion(completion)]; +} + ++ (BATContributionQueue *)firstQueue +{ + auto sort = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:YES]; + ContributionQueue *cq = [self firstOfClass:ContributionQueue.class + predicates:@[] + sortDescriptors:@[sort] + context:DataController.viewContext]; + if (!cq) { + return nil; + } + + BATContributionQueue *queue = [[BATContributionQueue alloc] init]; + queue.id = cq.id; + queue.partial = cq.partial; + queue.amount = cq.amount; + queue.type = static_cast(cq.type); + queue.publishers = ^NSArray *{ + NSMutableArray *pubs = [[NSMutableArray alloc] init]; + for (ContributionPublisher *pub in cq.publishers.allObjects) { + auto queuePublisher = [[BATContributionQueuePublisher alloc] init]; + queuePublisher.amountPercent = pub.amountPercent; + queuePublisher.publisherKey = pub.publisherKey; + [pubs addObject:queuePublisher]; + } + return [pubs copy]; + }(); + return queue; +} + ++ (void)deleteQueueWithID:(int64_t)queueID + completion:(nullable BATLedgerDatabaseWriteCompletion)completion +{ + [DataController.shared performOnContext:nil task:^(NSManagedObjectContext * _Nonnull context) { + const auto cq = [self getContributionQueueWithID:queueID context:context]; + if (!cq) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(NO); + }); + return; + } + [context deleteObject:cq]; + } completion:WriteToDataControllerCompletion(completion)]; +} + ++ (void)insertContributionPublishersIntoQueue:(ContributionQueue *)queue + publishers:(NSArray *)publishers + context:(NSManagedObjectContext *)context +{ + for (BATContributionQueuePublisher *publisher in publishers) { + const auto cp = [[ContributionPublisher alloc] initWithEntity:[NSEntityDescription entityForName:NSStringFromClass(ContributionPublisher.class) inManagedObjectContext:context] + insertIntoManagedObjectContext:context]; + cp.queue = queue; + cp.publisherKey = publisher.publisherKey; + cp.amountPercent = publisher.amountPercent; + } +} + #pragma mark - Activity Info + (void)insertOrUpdateActivityInfoFromPublisher:(BATPublisherInfo *)info completion:(nullable BATLedgerDatabaseWriteCompletion)completion diff --git a/vendor/brave-ios/Ledger/Data/Model.xcdatamodeld/Model.xcdatamodel/contents b/vendor/brave-ios/Ledger/Data/Model.xcdatamodeld/Model.xcdatamodel/contents index 4eee8bdd9110..87ac57ee6a1c 100644 --- a/vendor/brave-ios/Ledger/Data/Model.xcdatamodeld/Model.xcdatamodel/contents +++ b/vendor/brave-ios/Ledger/Data/Model.xcdatamodeld/Model.xcdatamodel/contents @@ -1,71 +1,83 @@ - + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + - - + + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - - + + + @@ -77,12 +89,12 @@ - - - - - - + + + + + + @@ -93,22 +105,22 @@ - - - - - - - + + + + + + + - - - - + + + + @@ -127,8 +139,10 @@ - + + + \ No newline at end of file diff --git a/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.h b/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.h new file mode 100644 index 000000000000..5aa4b02630eb --- /dev/null +++ b/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.h @@ -0,0 +1,22 @@ +/* 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/. */ + +#import +#import + +@class ContributionQueue; + +NS_ASSUME_NONNULL_BEGIN + +@interface ContributionPublisher : NSManagedObject + ++ (NSFetchRequest *)fetchRequest; + +@property (nullable, nonatomic, copy) NSString *publisherKey; +@property (nonatomic) double amountPercent; +@property (nullable, nonatomic, retain) ContributionQueue *queue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.m b/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.m new file mode 100644 index 000000000000..744b067c9c91 --- /dev/null +++ b/vendor/brave-ios/Ledger/Data/Model/ContributionPublisher.m @@ -0,0 +1,17 @@ +/* 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/. */ + +#import "ContributionPublisher.h" + +@implementation ContributionPublisher + ++ (NSFetchRequest *)fetchRequest { + return [NSFetchRequest fetchRequestWithEntityName:@"ContributionPublisher"]; +} + +@dynamic publisherKey; +@dynamic amountPercent; +@dynamic queue; + +@end diff --git a/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.h b/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.h new file mode 100644 index 000000000000..0171127ac7bc --- /dev/null +++ b/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.h @@ -0,0 +1,33 @@ +/* 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/. */ + +#import +#import + +@class ContributionPublisher; + +NS_ASSUME_NONNULL_BEGIN + +@interface ContributionQueue : NSManagedObject + ++ (NSFetchRequest *)fetchRequest; + +@property (nonatomic) int64_t id; +@property (nonatomic) int32_t type; +@property (nonatomic) double amount; +@property (nonatomic) bool partial; +@property (nullable, nonatomic, retain) NSSet *publishers; + +@end + +@interface ContributionQueue (CoreDataGeneratedAccessors) + +- (void)addPublishersObject:(ContributionPublisher *)value; +- (void)removePublishersObject:(ContributionPublisher *)value; +- (void)addPublishers:(NSSet *)values; +- (void)removePublishers:(NSSet *)values; + +@end + +NS_ASSUME_NONNULL_END diff --git a/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.m b/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.m new file mode 100644 index 000000000000..fe9e4a0f1cdc --- /dev/null +++ b/vendor/brave-ios/Ledger/Data/Model/ContributionQueue.m @@ -0,0 +1,19 @@ +/* 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/. */ + +#import "ContributionQueue.h" + +@implementation ContributionQueue + ++ (NSFetchRequest *)fetchRequest { + return [NSFetchRequest fetchRequestWithEntityName:@"ContributionQueue"]; +} + +@dynamic id; +@dynamic type; +@dynamic amount; +@dynamic partial; +@dynamic publishers; + +@end diff --git a/vendor/brave-ios/Ledger/Data/Model/CoreDataModels.h b/vendor/brave-ios/Ledger/Data/Model/CoreDataModels.h index a4278c590e8d..96bd7778ce52 100644 --- a/vendor/brave-ios/Ledger/Data/Model/CoreDataModels.h +++ b/vendor/brave-ios/Ledger/Data/Model/CoreDataModels.h @@ -20,3 +20,5 @@ #import "ServerPublisherAmount.h" #import "ServerPublisherBanner.h" #import "ServerPublisherLink.h" +#import "ContributionQueue.h" +#import "ContributionPublisher.h" diff --git a/vendor/brave-ios/Ledger/Generated/NativeLedgerClient.h b/vendor/brave-ios/Ledger/Generated/NativeLedgerClient.h index d73175b8dcc2..31bd3f4332fa 100644 --- a/vendor/brave-ios/Ledger/Generated/NativeLedgerClient.h +++ b/vendor/brave-ios/Ledger/Generated/NativeLedgerClient.h @@ -87,4 +87,7 @@ class NativeLedgerClient : public ledger::LedgerClient { std::string GetStringOption(const std::string& name) const override; int64_t GetInt64Option(const std::string& name) const override; uint64_t GetUint64Option(const std::string& name) const override; + void InsertOrUpdateContributionQueue(ledger::ContributionQueuePtr info, ledger::ResultCallback callback) override; + void DeleteContributionQueue(const uint64_t id, ledger::ResultCallback callback) override; + void GetFirstContributionQueue(ledger::GetFirstContributionQueueCallback callback) override; }; diff --git a/vendor/brave-ios/Ledger/Generated/NativeLedgerClient.mm b/vendor/brave-ios/Ledger/Generated/NativeLedgerClient.mm index 967d64b09679..00ae12acb069 100644 --- a/vendor/brave-ios/Ledger/Generated/NativeLedgerClient.mm +++ b/vendor/brave-ios/Ledger/Generated/NativeLedgerClient.mm @@ -228,4 +228,13 @@ } uint64_t NativeLedgerClient::GetUint64Option(const std::string& name) const { return [bridge_ getUint64Option:name]; +} +void NativeLedgerClient::InsertOrUpdateContributionQueue(ledger::ContributionQueuePtr info, ledger::ResultCallback callback) { + return [bridge_ insertOrUpdateContributionQueue:std::move(info) callback:callback]; +} +void NativeLedgerClient::DeleteContributionQueue(const uint64_t id, ledger::ResultCallback callback) { + return [bridge_ deleteContributionQueue:id callback:callback]; +} +void NativeLedgerClient::GetFirstContributionQueue(ledger::GetFirstContributionQueueCallback callback) { + return [bridge_ getFirstContributionQueue:callback]; } \ No newline at end of file diff --git a/vendor/brave-ios/Ledger/Generated/NativeLedgerClientBridge.h b/vendor/brave-ios/Ledger/Generated/NativeLedgerClientBridge.h index fe43dc0677d0..df3a8997317c 100644 --- a/vendor/brave-ios/Ledger/Generated/NativeLedgerClientBridge.h +++ b/vendor/brave-ios/Ledger/Generated/NativeLedgerClientBridge.h @@ -79,5 +79,8 @@ - (std::string)getStringOption:(const std::string&)name; - (int64_t)getInt64Option:(const std::string&)name; - (uint64_t)getUint64Option:(const std::string&)name; +- (void)insertOrUpdateContributionQueue:(ledger::ContributionQueuePtr)info callback:(ledger::ResultCallback)callback; +- (void)deleteContributionQueue:(const uint64_t) id callback:(ledger::ResultCallback)callback; +- (void)getFirstContributionQueue:(ledger::GetFirstContributionQueueCallback)callback; @end diff --git a/vendor/brave-ios/tests/ledger_database_test.mm b/vendor/brave-ios/tests/ledger_database_test.mm index b87338e21d83..76dbd143a4f3 100644 --- a/vendor/brave-ios/tests/ledger_database_test.mm +++ b/vendor/brave-ios/tests/ledger_database_test.mm @@ -1150,6 +1150,129 @@ - (void)testInsertPublisherListBannerForPublisherInfo } } +#pragma mark - Contribution Queue + +- (void)testInsertContributionQueue +{ + const auto queue = [[BATContributionQueue alloc] init]; + queue.id = 1; + queue.amount = 10; + [self waitForCompletion:^(XCTestExpectation *expectation) { + [BATLedgerDatabase insertOrUpdateContributionQueue:queue completion:^(BOOL success) { + XCTAssert(success); + [expectation fulfill]; + }]; + }]; + + const auto queried = [BATLedgerDatabase firstQueue]; + XCTAssertEqual(queried.id, queue.id); + XCTAssertEqual(queried.amount, queue.amount); +} + +- (void)testFirstContributionQueueSorting +{ + const auto queue = [[BATContributionQueue alloc] init]; + queue.id = 1; + queue.amount = 10; + [self waitForCompletion:^(XCTestExpectation *expectation) { + [BATLedgerDatabase insertOrUpdateContributionQueue:queue completion:^(BOOL success) { + XCTAssert(success); + [expectation fulfill]; + }]; + }]; + + const auto queue2 = [[BATContributionQueue alloc] init]; + queue2.id = 2; + queue2.amount = 10; + [self waitForCompletion:^(XCTestExpectation *expectation) { + [BATLedgerDatabase insertOrUpdateContributionQueue:queue2 completion:^(BOOL success) { + XCTAssert(success); + [expectation fulfill]; + }]; + }]; + + const auto queried = [BATLedgerDatabase firstQueue]; + XCTAssertEqual(queried.id, queue.id); + XCTAssertEqual(queried.amount, queue.amount); +} + +- (void)testEmptyContributionQueue +{ + const auto queried = [BATLedgerDatabase firstQueue]; + XCTAssertNil(queried); +} + +- (void)testDeleteContributionQueue +{ + const auto queue = [[BATContributionQueue alloc] init]; + queue.id = 1; + queue.amount = 10; + [self waitForCompletion:^(XCTestExpectation *expectation) { + [BATLedgerDatabase insertOrUpdateContributionQueue:queue completion:^(BOOL success) { + XCTAssert(success); + [expectation fulfill]; + }]; + }]; + + const auto queue2 = [[BATContributionQueue alloc] init]; + queue2.id = 2; + queue2.amount = 10; + [self waitForCompletion:^(XCTestExpectation *expectation) { + [BATLedgerDatabase insertOrUpdateContributionQueue:queue2 completion:^(BOOL success) { + XCTAssert(success); + [expectation fulfill]; + }]; + }]; + + // Delete the first queue, therefore firstQueue should return the second one + [self waitForCompletion:^(XCTestExpectation *expectation) { + [BATLedgerDatabase deleteQueueWithID:queue.id completion:^(BOOL success) { + XCTAssert(success); + [expectation fulfill]; + }]; + }]; + + const auto queried = [BATLedgerDatabase firstQueue]; + XCTAssertEqual(queried.id, queue2.id); + XCTAssertEqual(queried.amount, queue2.amount); +} + +- (void)testContributionQueueWithPublishers +{ + const auto queue = [[BATContributionQueue alloc] init]; + queue.id = 1; + queue.amount = 10; + + const auto pub1 = [[BATContributionQueuePublisher alloc] init]; + pub1.publisherKey = @"brave.com"; + pub1.amountPercent = 0.6; + + const auto pub2 = [[BATContributionQueuePublisher alloc] init]; + pub2.publisherKey = @"duckduckgo.com"; + pub2.amountPercent = 0.4; + + queue.publishers = @[ pub1, pub2 ]; + + [self waitForCompletion:^(XCTestExpectation *expectation) { + [BATLedgerDatabase insertOrUpdateContributionQueue:queue completion:^(BOOL success) { + XCTAssert(success); + [expectation fulfill]; + }]; + }]; + + const auto queried = [BATLedgerDatabase firstQueue]; + XCTAssertEqual(queried.publishers.count, queue.publishers.count); + const auto pub1Index = [queried.publishers indexOfObjectPassingTest:^BOOL(BATContributionQueuePublisher * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + return [obj.publisherKey isEqualToString:pub1.publisherKey]; + }]; + XCTAssertNotEqual(pub1Index, NSNotFound); + const auto pub2Index = (pub1Index == 0 ? 1 : 0); + + XCTAssertEqual(queried.publishers[pub1Index].amountPercent, pub1.amountPercent); + XCTAssert([queried.publishers[pub2Index].publisherKey isEqualToString:pub2.publisherKey]); + XCTAssertEqual(queried.publishers[pub2Index].amountPercent, pub2.amountPercent); +} + #pragma mark - - (void)waitForCompletion:(void (^)(XCTestExpectation *))task