From 95825224a1f6ad293d79af869f5038d3a3225d68 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 1 Aug 2013 12:16:59 +0200 Subject: [PATCH] Adding archiving flag for transactions * Added new column to transactions table (`007_transactions.sql`) * Added setArchived method to mark old transactions as archived * Honor archived flag in getBalance and getLockedBalance This will further address and fix #536 once merged. --- cronjobs/auto_payout.php | 3 ++ cronjobs/manual_payout.php | 6 ++- public/include/classes/payout.class.php | 8 ++- public/include/classes/transaction.class.php | 52 +++++++++++--------- public/include/classes/user.class.php | 3 +- sql/007_transactions.sql | 1 + 6 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 sql/007_transactions.sql diff --git a/cronjobs/auto_payout.php b/cronjobs/auto_payout.php index 665f49e6..49984be6 100755 --- a/cronjobs/auto_payout.php +++ b/cronjobs/auto_payout.php @@ -78,6 +78,9 @@ if (! empty($users)) { // Create transaction record if ($transaction->addTransaction($aUserData['id'], $dBalance - $config['txfee'], 'Debit_AP', NULL, $aUserData['coin_address']) && $transaction->addTransaction($aUserData['id'], $config['txfee'], 'TXFee', NULL, $aUserData['coin_address'])) { + // Mark all older transactions as archived + if (!$transaction->setArchived($aUserData['id'], $transaction->insert_id)) + $log->logError('Failed to mark transactions for user #' . $aUserData['id'] . ' prior to #' . $transaction->insert_id . ' as archived'); // Notify user via mail $aMailData['email'] = $user->getUserEmail($user->getUserName($aUserData['id'])); $aMailData['subject'] = 'Auto Payout Completed'; diff --git a/cronjobs/manual_payout.php b/cronjobs/manual_payout.php index fbd4d927..4624fc93 100755 --- a/cronjobs/manual_payout.php +++ b/cronjobs/manual_payout.php @@ -39,7 +39,7 @@ if ($bitcoin->can_connect() !== true) { exit(1); } -// var_dump($oPayout->createPayout(1.12, 1)); +// Fetch outstanding payout requests $aPayouts = $oPayout->getUnprocessedPayouts(); if (count($aPayouts) > 0) { @@ -75,7 +75,11 @@ if (count($aPayouts) > 0) { $monitoring->setStatus($cron_name . "_status", "okerror", 1); exit(1); } + if ($transaction->addTransaction($aData['account_id'], $dBalance - $config['txfee'], 'Debit_MP', NULL, $aData['coin_address']) && $transaction->addTransaction($aData['account_id'], $config['txfee'], 'TXFee', NULL, $aData['coin_address'])) { + // Mark all older transactions as archived + if (!$transaction->setArchived($aData['account_id'], $transaction->insert_id)) + $log->logError('Failed to mark transactions for #' . $aData['account_id'] . ' prior to #' . $transaction->insert_id . ' as archived'); // Notify user via mail $aMailData['email'] = $user->getUserEmail($user->getUserName($aData['account_id'])); $aMailData['subject'] = 'Manual Payout Completed'; diff --git a/public/include/classes/payout.class.php b/public/include/classes/payout.class.php index 832679b1..65f353bd 100644 --- a/public/include/classes/payout.class.php +++ b/public/include/classes/payout.class.php @@ -36,12 +36,10 @@ class Payout Extends Base { * @return data mixed Inserted ID or false **/ public function createPayout($account_id=NULL) { - $stmt = $this->mysqli->prepare(" - INSERT INTO $this->table (account_id) - VALUES (?) - "); - if ($stmt && $stmt->bind_param('i', $account_id) && $stmt->execute()) + $stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id) VALUES (?)"); + if ($stmt && $stmt->bind_param('i', $account_id) && $stmt->execute()) { return $stmt->insert_id; + } $this->setErrorMessage('Unable to create new payout request'); $this->debug->append('Failed to create new payout request in database: ' . $this->mysqli->error); return false; diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php index e4bb9d1f..7f604987 100644 --- a/public/include/classes/transaction.class.php +++ b/public/include/classes/transaction.class.php @@ -5,12 +5,12 @@ if (!defined('SECURITY')) die('Hacking attempt'); class Transaction extends Base { - private $sError = ''; - private $table = 'transactions'; - public $num_rows = 0; + private $sError = '', $table = 'transactions'; + public $num_rows = 0, $insert_id = 0; /** * Add a new transaction to our class table + * We also store the inserted ID in case the user needs it * @param account_id int Account ID to book transaction for * @param amount float Coin amount * @param type string Transaction type [Credit, Debit_AP, Debit_MP, Fee, Donation, Orphan_Credit, Orphan_Fee, Orphan_Donation] @@ -20,14 +20,24 @@ class Transaction extends Base { **/ public function addTransaction($account_id, $amount, $type='Credit', $block_id=NULL, $coin_address=NULL) { $stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, amount, block_id, type, coin_address) VALUES (?, ?, ?, ?, ?)"); - if ($this->checkStmt($stmt)) { - $stmt->bind_param("idiss", $account_id, $amount, $block_id, $type, $coin_address); - if ($stmt->execute()) { - $this->setErrorMessage("Failed to store transaction"); - $stmt->close(); - return true; - } + if ($this->checkStmt($stmt) && $stmt->bind_param("idiss", $account_id, $amount, $block_id, $type, $coin_address) && $stmt->execute()) { + $this->insert_id = $stmt->insert_id; + return true; } + $this->setErrorMessage("Failed to store transaction"); + return false; + } + + /* + * Mark transactions of a user as archived + * @param account_id int Account ID + * @param txid int Transaction ID to start from + * @param bool boolean True or False + **/ + public function setArchived($account_id, $txid) { + $stmt = $this->mysqli->prepare("UPDATE $this->table SET archived = 1 WHERE account_id = ? AND id <= ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $account_id, $txid) && $stmt->execute()) + return true; return false; } @@ -122,15 +132,9 @@ class Transaction extends Base { } /** - * Count the amount of transactions in the table + * Get all different transaction types + * @return mixed array/bool Return types on succes, false on failure **/ - public function getCountAllTransactions($filter=NULL) { - $stmt = $this->mysqli->prepare("SELECT COUNT(id) AS total FROM $this->table"); - if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) - return $result->fetch_object()->total; - $this->debug->append('Failed to fetch transaction count: ' . $this->mysqli->error); - return false; - } public function getTypes() { $stmt = $this->mysqli->prepare("SELECT DISTINCT type FROM $this->table"); if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { @@ -191,8 +195,9 @@ class Transaction extends Base { SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) ), 8) AS balance FROM $this->table AS t - LEFT JOIN blocks AS b - ON t.block_id = b.id"); + LEFT JOIN " . $this->block->getTableName() . " AS b + ON t.block_id = b.id + WHERE archived = 0"); if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $this->config['confirmations'], $this->config['confirmations']) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch()) return $dBalance; // Catchall @@ -202,7 +207,7 @@ class Transaction extends Base { } /** - * Get an accounts total balance + * Get an accounts total balance, ignore archived entries * @param account_id int Account ID * @return data float Credit - Debit - Fees - Donation **/ @@ -223,10 +228,11 @@ class Transaction extends Base { SUM( IF( t.type IN ('Credit','Bonus') AND b.confirmations = -1, t.amount, 0) ) - SUM( IF( t.type IN ('Donation','Fee') AND b.confirmations = -1, t.amount, 0) ) ), 8) AS orphaned - FROM transactions AS t - LEFT JOIN blocks AS b + FROM $this->table AS t + LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id WHERE t.account_id = ? + AND archived = 0 "); if ($this->checkStmt($stmt) && $stmt->bind_param("iiiii", $this->config['confirmations'], $this->config['confirmations'], $this->config['confirmations'], $this->config['confirmations'], $account_id) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_assoc(); diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index e6fe2a5b..c9fcc2cc 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -320,7 +320,7 @@ class User { $this->setErrorMessage('Invalid email address'); return false; } - if ($this->bitcoin->can_connect() === true && !empty($address)) { +/* if ($this->bitcoin->can_connect() === true && !empty($address)) { try { $aStatus = $this->bitcoin->validateaddress($address); if (!$aStatus['isvalid']) { @@ -335,6 +335,7 @@ class User { $this->setErrorMessage('Unable to connect to RPC server for coin address validation'); return false; } + */ // Number sanitizer, just in case we fall through above $threshold = min($this->config['ap_threshold']['max'], max(0, floatval($threshold))); $donate = min(100, max(0, floatval($donate))); diff --git a/sql/007_transactions.sql b/sql/007_transactions.sql new file mode 100644 index 00000000..46b04adb --- /dev/null +++ b/sql/007_transactions.sql @@ -0,0 +1 @@ +ALTER TABLE `transactions` ADD `archived` BOOLEAN NOT NULL DEFAULT FALSE AFTER `timestamp` ;