Merge pull request #2274 from MPOS/development

UPDATE : Development to Master
This commit is contained in:
Sebastian Grewe 2014-08-18 09:04:50 +02:00
commit 86df6d1e3e
52 changed files with 653 additions and 392 deletions

4
.gitignore vendored
View File

@ -18,6 +18,10 @@
/include/config/global.inc.scrypt.php /include/config/global.inc.scrypt.php
/include/config/global.inc.sha.php /include/config/global.inc.sha.php
# Test files
/scripts/test.php
/cronjobs/test.php
# IDE Settings # IDE Settings
/.idea/* /.idea/*
.buildpath .buildpath

View File

@ -59,7 +59,7 @@ if (empty($aTransactions['transactions'])) {
$config['reward_type'] == 'block' ? $aData['amount'] = $aData['amount'] : $aData['amount'] = $config['reward']; $config['reward_type'] == 'block' ? $aData['amount'] = $aData['amount'] : $aData['amount'] = $config['reward'];
$aData['height'] = $aBlockRPCInfo['height']; $aData['height'] = $aBlockRPCInfo['height'];
$aTxDetails = $bitcoin->gettransaction($aBlockRPCInfo['tx'][0]); $aTxDetails = $bitcoin->gettransaction($aBlockRPCInfo['tx'][0]);
if (!isset($aBlockRPCInfo['confirmations'])) { if (isset($aBlockRPCInfo['confirmations'])) {
$aData['confirmations'] = $aBlockRPCInfo['confirmations']; $aData['confirmations'] = $aBlockRPCInfo['confirmations'];
} else if (isset($aTxDetails['confirmations'])) { } else if (isset($aTxDetails['confirmations'])) {
$aData['confirmations'] = $aTxDetails['confirmations']; $aData['confirmations'] = $aTxDetails['confirmations'];

View File

@ -27,7 +27,7 @@ require_once('shared.inc.php');
// Header // Header
$log->logInfo('Running statistical queries, errors may just mean no shares were available'); $log->logInfo('Running statistical queries, errors may just mean no shares were available');
$strLogMask = "| %-26.26s | %8.8s | %-6.6s |"; $strLogMask = "| %-33.33s | %8.8s | %-6.6s |";
$log->logInfo(sprintf($strLogMask, 'Method', 'Runtime', 'Status')); $log->logInfo(sprintf($strLogMask, 'Method', 'Runtime', 'Status'));
// Per user share statistics based on all shares submitted // Per user share statistics based on all shares submitted
@ -37,9 +37,15 @@ $log->logInfo(sprintf($strLogMask, 'getAllUserShares', number_format(microtime(t
// Get all user hashrate statistics for caching // Get all user hashrate statistics for caching
$start = microtime(true); $start = microtime(true);
$statistics->getAllUserMiningStats() ? $status = 'OK' : $status = 'ERROR'; $statistics->fetchAllUserMiningStats() ? $status = 'OK' : $status = 'ERROR';
$log->logInfo(sprintf($strLogMask, 'getAllUserMiningStats', number_format(microtime(true) - $start, 3), $status)); $log->logInfo(sprintf($strLogMask, 'fetchAllUserMiningStats', number_format(microtime(true) - $start, 3), $status));
// Store our statistical data into our `statistics_users` table
$start = microtime(true);
$statistics->storeAllUserMiningStatsSnapshot($statistics->getAllUserMiningStats()) ? $status = 'OK' : $status = 'ERROR';
$log->logInfo(sprintf($strLogMask, 'storeAllUserMiningStatsSnapshot', number_format(microtime(true) - $start, 3), $status));
// Get stats for pool overview
$start = microtime(true); $start = microtime(true);
$statistics->getTopContributors('hashes') ? $status = 'OK' : $status = 'ERROR'; $statistics->getTopContributors('hashes') ? $status = 'OK' : $status = 'ERROR';
$log->logInfo(sprintf($strLogMask, 'getTopContributors(hashes)', number_format(microtime(true) - $start, 3), $status)); $log->logInfo(sprintf($strLogMask, 'getTopContributors(hashes)', number_format(microtime(true) - $start, 3), $status));

View File

@ -65,7 +65,7 @@ $status = 'OK';
$message = ''; $message = '';
$affected = $share->purgeArchive(); $affected = $share->purgeArchive();
if ($affected === false) { if ($affected === false) {
$message = 'Failed to delete notifications: ' . $oToken->getCronError(); $message = 'Failed to delete shares: ' . $share->getCronError();
$status = 'ERROR'; $status = 'ERROR';
$monitoring->endCronjob($cron_name, 'E0008', 0, false, false); $monitoring->endCronjob($cron_name, 'E0008', 0, false, false);
} else { } else {
@ -73,6 +73,19 @@ if ($affected === false) {
} }
$log->logInfo(sprintf($strLogMask, 'purgeArchive', $affected, number_format(microtime(true) - $start, 3), $status, $message)); $log->logInfo(sprintf($strLogMask, 'purgeArchive', $affected, number_format(microtime(true) - $start, 3), $status, $message));
// Clenaup shares archive
$start = microtime(true);
$status = 'OK';
$message = '';
$affected = $statistics->purgeUserStats($setting->getValue('statistics_graphing_days', 1));
if ($affected === false) {
$message = 'Failed to delete entries: ' . $statistics->getCronError();
$status = 'ERROR';
$monitoring->endCronjob($cron_name, 'E0008', 0, false, false);
} else {
$affected == 0 ? $message = 'No entries deleted' : $message = 'Deleted old entries';
}
$log->logInfo(sprintf($strLogMask, 'purgeUserStats', $affected, number_format(microtime(true) - $start, 3), $status, $message));
// Cron cleanup and monitoring // Cron cleanup and monitoring
require_once('cron_end.inc.php'); require_once('cron_end.inc.php');

View File

@ -16,6 +16,7 @@ require_once(INCLUDE_DIR . '/config/error_codes.inc.php');
// We need to load these first // We need to load these first
require_once(CLASS_DIR . '/base.class.php'); require_once(CLASS_DIR . '/base.class.php');
require_once(CLASS_DIR . '/coins/coin_base.class.php'); require_once(CLASS_DIR . '/coins/coin_base.class.php');
require_once(CLASS_DIR . '/coin_address.class.php');
require_once(CLASS_DIR . '/setting.class.php'); require_once(CLASS_DIR . '/setting.class.php');
require_once(INCLUDE_DIR . '/version.inc.php'); require_once(INCLUDE_DIR . '/version.inc.php');
if (PHP_OS == 'WINNT') require_once(CLASS_DIR . '/memcached.class.php'); if (PHP_OS == 'WINNT') require_once(CLASS_DIR . '/memcached.class.php');

View File

@ -22,6 +22,9 @@ class Base {
public function setCoin($coin) { public function setCoin($coin) {
$this->coin = $coin; $this->coin = $coin;
} }
public function setCoinAddress($coin_address) {
$this->coin_address = $coin_address;
}
public function setLog($log) { public function setLog($log) {
$this->log = $log; $this->log = $log;
} }

View File

@ -0,0 +1,107 @@
<?php
$defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
class CoinAddress extends Base {
protected $table = 'coin_addresses';
private $cache = array();
/**
* Fetch users coin address for a currency
* @param userID int UserID
* @return data string Coin Address
**/
public function getCoinAddress($userID, $currency=NULL) {
if ($currency === NULL) $currency = $this->config['currency'];
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
SELECT coin_address
FROM " . $this->getTableName() . "
WHERE account_id = ? AND currency = ?
");
if ( $this->checkStmt($stmt) && $stmt->bind_param('is', $userID, $currency) && $stmt->execute() && $result = $stmt->get_result()) {
if ($result->num_rows == 1) {
return $result->fetch_object()->coin_address;
}
}
$this->debug->append("Unable to fetch users coin address for " . $currency);
return $this->sqlError();
}
/**
* Check if a coin address is already set
* @param address string Coin Address to check for
* @return bool true or false
**/
public function existsCoinAddress($address) {
$this->debug->append("STA " . __METHOD__, 4);
return $this->getSingle($address, 'coin_address', 'coin_address', 's') === $address;
}
/**
* Add a new coin address record for a user
* @param userID int Account ID
* @param address string Coin Address
* @param currency string Currency short handle, defaults to config option
* @return bool true or false
**/
public function add($userID, $address, $currency=NULL) {
if ($currency === NULL) $currency = $this->config['currency'];
if ($address != $this->getCoinAddress($userID) && $this->existsCoinAddress($address)) {
$this->setErrorMessage('Unable to update coin address, address already exists');
return false;
}
$stmt = $this->mysqli->prepare("INSERT INTO " . $this->getTableName() . " (account_id, currency, coin_address) VALUES (?, ?, ?)");
if ( $this->checkStmt($stmt) && $stmt->bind_param('iss', $userID, $currency, $address) && $stmt->execute()) {
return true;
}
return $this->sqlError();
}
/**
* Remove a coin address record for a user
* @param userID int Account ID
* @param currency string Currency short handle, defaults to config option
* @return bool true or false
**/
public function remove ($userID, $currency=NULL) {
if ($currency === NULL) $currency = $this->config['currency'];
$stmt = $this->mysqli->prepare("DELETE FROM " . $this->getTableName() . " WHERE account_id = ? AND currency = ?");
if ( $this->checkStmt($stmt) && $stmt->bind_param('is', $userID, $currency) && $stmt->execute()) {
return true;
}
return $this->sqlError();
}
/**
* Update a coin address record for a user and a currency
* @param userID int Account ID
* @param address string Coin Address
* @param currency string Currency short handle, defaults to config option
* @return bool true or false
**/
public function update($userID, $address, $currency=NULL) {
if ($currency === NULL) $currency = $this->config['currency'];
if ($address != $this->getCoinAddress($userID) && $this->existsCoinAddress($address)) {
$this->setErrorMessage('Unable to update coin address, address already exists');
return false;
}
if ($this->getCoinAddress($userID) != NULL) {
$stmt = $this->mysqli->prepare("UPDATE " . $this->getTableName() . " SET coin_address = ? WHERE account_id = ? AND currency = ?");
if ( $this->checkStmt($stmt) && $stmt->bind_param('sis', $address, $userID, $currency) && $stmt->execute()) {
return true;
}
} else {
$stmt = $this->mysqli->prepare("INSERT INTO " . $this->getTableName() . " (coin_address, account_id, currency) VALUES (?, ?, ?)");
if ( $this->checkStmt($stmt) && $stmt->bind_param('sis', $address, $userID, $currency) && $stmt->execute()) {
return true;
}
}
return $this->sqlError();
}
}
$coin_address = new CoinAddress();
$coin_address->setDebug($debug);
$coin_address->setConfig($config);
$coin_address->setMysql($mysqli);
$coin_address->setErrorCodes($aErrorCodes);

View File

@ -12,6 +12,9 @@ class CoinBase extends Base {
// Our coins target bits // Our coins target bits
protected $target_bits = NULL; protected $target_bits = NULL;
// Our coins share difficulty precision
protected $share_difficulty_precision = 0;
/** /**
* Read our target bits * Read our target bits
**/ **/
@ -19,6 +22,13 @@ class CoinBase extends Base {
return $this->target_bits; return $this->target_bits;
} }
/**
* Read our share difficulty precision
**/
public function getShareDifficultyPrecision() {
return $this->share_difficulty_precision;
}
/** /**
* Calculate the PPS value for this coin * Calculate the PPS value for this coin
* WARNING: Get this wrong and you will over- or underpay your miners! * WARNING: Get this wrong and you will over- or underpay your miners!

View File

@ -8,6 +8,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
**/ **/
class Coin extends CoinBase { class Coin extends CoinBase {
protected $target_bits = 24; protected $target_bits = 24;
protected $share_difficulty_precision = 4;
} }
?> ?>

View File

@ -9,6 +9,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
**/ **/
class Statistics extends Base { class Statistics extends Base {
protected $table = 'statistics_shares'; protected $table = 'statistics_shares';
protected $table_user_stats = 'statistics_users';
private $getcache = true; private $getcache = true;
// Disable fetching values from cache // Disable fetching values from cache
@ -18,6 +19,12 @@ class Statistics extends Base {
public function getGetCache() { public function getGetCache() {
return $this->getcache; return $this->getcache;
} }
public function getAllUserMiningStats() {
return $this->allUserMiningStats;
}
public function getUserStatsTableName() {
return $this->table_user_stats;
}
/** /**
* Get our first block found * Get our first block found
@ -45,37 +52,37 @@ class Statistics extends Base {
IFNULL(SUM(IF(confirmations > 0, 1, 0)), 0) AS TotalValid, IFNULL(SUM(IF(confirmations > 0, 1, 0)), 0) AS TotalValid,
IFNULL(SUM(IF(confirmations = -1, 1, 0)), 0) AS TotalOrphan, IFNULL(SUM(IF(confirmations = -1, 1, 0)), 0) AS TotalOrphan,
IFNULL(SUM(IF(confirmations > 0, difficulty, 0)), 0) AS TotalDifficulty, IFNULL(SUM(IF(confirmations > 0, difficulty, 0)), 0) AS TotalDifficulty,
IFNULL(ROUND(SUM(IF(confirmations > -1, shares, 0))), 0) AS TotalShares, IFNULL(SUM(IF(confirmations > -1, shares, 0)), 0) AS TotalShares,
IFNULL(SUM(IF(confirmations > -1, amount, 0)), 0) AS TotalAmount, IFNULL(SUM(IF(confirmations > -1, amount, 0)), 0) AS TotalAmount,
IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourTotal, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourTotal,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourValid, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourValid,
IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourOrphan, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourOrphan,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), difficulty, 0)), 0) AS 1HourDifficulty, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), difficulty, 0)), 0) AS 1HourDifficulty,
IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), shares, 0))), 0) AS 1HourShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), shares, 0)), 0) AS 1HourShares,
IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), amount, 0)), 0) AS 1HourAmount, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), amount, 0)), 0) AS 1HourAmount,
IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourTotal, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourTotal,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourValid, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourValid,
IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourOrphan, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourOrphan,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), difficulty, 0)), 0) AS 24HourDifficulty, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), difficulty, 0)), 0) AS 24HourDifficulty,
IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), shares, 0))), 0) AS 24HourShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), shares, 0)), 0) AS 24HourShares,
IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), amount, 0)), 0) AS 24HourAmount, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), amount, 0)), 0) AS 24HourAmount,
IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysTotal, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysTotal,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysValid, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysValid,
IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysOrphan, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysOrphan,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), difficulty, 0)), 0) AS 7DaysDifficulty, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), difficulty, 0)), 0) AS 7DaysDifficulty,
IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), shares, 0))), 0) AS 7DaysShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), shares, 0)), 0) AS 7DaysShares,
IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), amount, 0)), 0) AS 7DaysAmount, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), amount, 0)), 0) AS 7DaysAmount,
IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksTotal, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksTotal,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksValid, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksValid,
IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksOrphan, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksOrphan,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), difficulty, 0)), 0) AS 4WeeksDifficulty, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), difficulty, 0)), 0) AS 4WeeksDifficulty,
IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), shares, 0))), 0) AS 4WeeksShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), shares, 0)), 0) AS 4WeeksShares,
IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), amount, 0)), 0) AS 4WeeksAmount, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), amount, 0)), 0) AS 4WeeksAmount,
IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthTotal, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthTotal,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthValid, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthValid,
IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthOrphan, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthOrphan,
IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), difficulty, 0)), 0) AS 12MonthDifficulty, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), difficulty, 0)), 0) AS 12MonthDifficulty,
IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), shares, 0))), 0) AS 12MonthShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), shares, 0)), 0) AS 12MonthShares,
IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), amount, 0)), 0) AS 12MonthAmount IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), amount, 0)), 0) AS 12MonthAmount
FROM " . $this->block->getTableName()); FROM " . $this->block->getTableName());
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) {
@ -127,7 +134,7 @@ class Statistics extends Base {
b.*, b.*,
a.username AS finder, a.username AS finder,
a.is_anonymous AS is_anonymous, a.is_anonymous AS is_anonymous,
ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0) AS estshares ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 4) AS estshares
FROM " . $this->block->getTableName() . " AS b FROM " . $this->block->getTableName() . " AS b
LEFT JOIN " . $this->user->getTableName() . " AS a LEFT JOIN " . $this->user->getTableName() . " AS a
ON b.account_id = a.id ON b.account_id = a.id
@ -163,7 +170,7 @@ class Statistics extends Base {
return $this->memcache->setCache(__FUNCTION__ . $limit, $result->fetch_all(MYSQLI_ASSOC), 5); return $this->memcache->setCache(__FUNCTION__ . $limit, $result->fetch_all(MYSQLI_ASSOC), 5);
return $this->sqlError(); return $this->sqlError();
} }
/** /**
* Get SUM of blocks found and generated Coins for each worker * Get SUM of blocks found and generated Coins for each worker
* @param limit int Last limit blocks * @param limit int Last limit blocks
@ -185,7 +192,7 @@ class Statistics extends Base {
return $this->memcache->setCache(__FUNCTION__ . $account_id . $limit, $result->fetch_all(MYSQLI_ASSOC), 5); return $this->memcache->setCache(__FUNCTION__ . $account_id . $limit, $result->fetch_all(MYSQLI_ASSOC), 5);
return $this->sqlError(); return $this->sqlError();
} }
/** /**
* Currently the only function writing to the database * Currently the only function writing to the database
* Stored per block user statistics of valid and invalid shares * Stored per block user statistics of valid and invalid shares
@ -223,12 +230,12 @@ class Statistics extends Base {
SELECT SELECT
( (
( (
SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty))), 0) AS shares SELECT IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares
FROM " . $this->share->getTableName() . " FROM " . $this->share->getTableName() . "
WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) WHERE time > DATE_SUB(now(), INTERVAL ? SECOND)
AND our_result = 'Y' AND our_result = 'Y'
) + ( ) + (
SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty))), 0) AS shares SELECT IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares
FROM " . $this->share->getArchiveTableName() . " FROM " . $this->share->getArchiveTableName() . "
WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) WHERE time > DATE_SUB(now(), INTERVAL ? SECOND)
AND our_result = 'Y' AND our_result = 'Y'
@ -254,12 +261,12 @@ class Statistics extends Base {
SELECT SELECT
( (
( (
SELECT ROUND(COUNT(id) / ?, 2) AS sharerate SELECT ROUND(SUM(difficulty) / ?, 2) AS sharerate
FROM " . $this->share->getTableName() . " FROM " . $this->share->getTableName() . "
WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) WHERE time > DATE_SUB(now(), INTERVAL ? SECOND)
AND our_result = 'Y' AND our_result = 'Y'
) + ( ) + (
SELECT ROUND(COUNT(id) / ?, 2) AS sharerate SELECT ROUND(SUM(difficulty) / ?, 2) AS sharerate
FROM " . $this->share->getArchiveTableName() . " FROM " . $this->share->getArchiveTableName() . "
WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) WHERE time > DATE_SUB(now(), INTERVAL ? SECOND)
AND our_result = 'Y' AND our_result = 'Y'
@ -293,8 +300,8 @@ class Statistics extends Base {
} }
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
ROUND(IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS valid, IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS valid,
ROUND(IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS invalid IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS invalid
FROM " . $this->share->getTableName() . " FROM " . $this->share->getTableName() . "
WHERE UNIX_TIMESTAMP(time) > IFNULL((SELECT MAX(time) FROM " . $this->block->getTableName() . "), 0)"); WHERE UNIX_TIMESTAMP(time) > IFNULL((SELECT MAX(time) FROM " . $this->block->getTableName() . "), 0)");
if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() ) if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() )
@ -316,8 +323,8 @@ class Statistics extends Base {
} }
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
ROUND(IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0), 0) AS valid, IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) AS valid,
ROUND(IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0), 0) AS invalid, IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) AS invalid,
u.id AS id, u.id AS id,
u.donate_percent AS donate_percent, u.donate_percent AS donate_percent,
u.is_anonymous AS is_anonymous, u.is_anonymous AS is_anonymous,
@ -368,11 +375,11 @@ class Statistics extends Base {
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
ROUND(IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS valid, IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS valid,
ROUND(IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS invalid IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS invalid
FROM " . $this->share->getTableName() . " FROM " . $this->share->getTableName() . "
WHERE username LIKE ? WHERE username LIKE ?
AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(b.time) FROM " . $this->block->getTableName() . " AS b),0)"); AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(b.time) FROM " . $this->block->getTableName() . " AS b),0)");
$username = $username . ".%"; $username = $username . ".%";
if ($stmt && $stmt->bind_param("s", $username) && $stmt->execute() && $result = $stmt->get_result()) if ($stmt && $stmt->bind_param("s", $username) && $stmt->execute() && $result = $stmt->get_result())
return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc()); return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc());
@ -451,16 +458,19 @@ class Statistics extends Base {
/** /**
* Fetch all user hashrates based on shares and archived shares * Fetch all user hashrates based on shares and archived shares
* Store it in cache, also keep a copy of the data internally to
* return it for further processing
* @return data array Set of all user stats * @return data array Set of all user stats
**/ **/
public function getAllUserMiningStats($interval=180) { public function fetchAllUserMiningStats($interval=180) {
$this->debug->append("STA " . __METHOD__, 4); $this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
a.id AS id, a.id AS id,
a.username AS account, a.username AS account,
COUNT(DISTINCT t1.username) AS workers,
IFNULL(SUM(t1.difficulty), 0) AS shares, IFNULL(SUM(t1.difficulty), 0) AS shares,
ROUND(COUNT(t1.id) / ?, 2) AS sharerate, ROUND(SUM(t1.difficulty) / ?, 2) AS sharerate,
IFNULL(AVG(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS avgsharediff IFNULL(AVG(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS avgsharediff
FROM ( FROM (
SELECT SELECT
@ -489,18 +499,51 @@ class Statistics extends Base {
$aData['data'][$row['id']] = $row; $aData['data'][$row['id']] = $row;
$aData['data'][$row['id']]['hashrate'] = $this->coin->calcHashrate($row['shares'], $interval); $aData['data'][$row['id']]['hashrate'] = $this->coin->calcHashrate($row['shares'], $interval);
} }
$this->allUserMiningStats = $aData;
return $this->memcache->setStaticCache(STATISTICS_ALL_USER_HASHRATES, $aData, 600); return $this->memcache->setStaticCache(STATISTICS_ALL_USER_HASHRATES, $aData, 600);
} else { } else {
return $this->sqlError(); return $this->sqlError();
} }
} }
/**
* Store our gathered data into our statistic table for users
* @param aData array Data created by fetchAllUserMiningStats
* @return bool true or false
**/
public function storeAllUserMiningStatsSnapshot($aData) {
$this->debug->append("STA " . __METHOD__, 4);
if (!isset($aData['data'])) return false;
// initilize
$timestamp = time(); // Store all entries with the same timestamp to reduce cardinality
$ok = 0;
$failed = 0;
foreach ($aData['data'] as $key => $aUserData) {
$stmt = $this->mysqli->prepare("
INSERT INTO " . $this->getUserStatsTableName() . "
( account_id, hashrate, workers, sharerate, timestamp ) VALUES ( ?, ?, ?, ?, ?)");
if ($this->checkStmt($stmt) && $stmt->bind_param("ididi", $aUserData['id'], $aUserData['hashrate'], $aUserData['workers'], $aUserData['sharerate'], $timestamp) && $stmt->execute() ) {
$ok++;
} else {
$failed++;
}
}
return array('ok' => $ok, 'failed' => $failed);
}
/**
* Fetch unpaid PPS shares for an account
* @param username string Username
* @param account_id int User ID
* @param last_paid_pps_id int Last paid out share by pps_payout cron
* @return data int Sum of unpaid diff1 shares
**/
public function getUserUnpaidPPSShares($username, $account_id=NULL, $last_paid_pps_id) { public function getUserUnpaidPPSShares($username, $account_id=NULL, $last_paid_pps_id) {
$this->debug->append("STA " . __METHOD__, 4); $this->debug->append("STA " . __METHOD__, 4);
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
ROUND(IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0), 0) AS total IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS total
FROM " . $this->share->getTableName() . " FROM " . $this->share->getTableName() . "
WHERE username LIKE ? WHERE username LIKE ?
AND id > ? AND id > ?
@ -515,7 +558,7 @@ class Statistics extends Base {
* Get Shares per x interval by user * Get Shares per x interval by user
* @param username string username * @param username string username
* @param $account_id int account id * @param $account_id int account id
* @return data integer Current Sharerate in shares/s * @return data integer Current Sharerate in diff1 shares/s
**/ **/
public function getUserMiningStats($username, $account_id=NULL, $interval=180) { public function getUserMiningStats($username, $account_id=NULL, $interval=180) {
$this->debug->append("STA " . __METHOD__, 4); $this->debug->append("STA " . __METHOD__, 4);
@ -532,7 +575,7 @@ class Statistics extends Base {
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
IFNULL(COUNT(*) / ?, 0) AS sharerate, IFNULL(SUM(difficulty) / ?, 0) AS sharerate,
IFNULL(SUM(difficulty), 0) AS shares, IFNULL(SUM(difficulty), 0) AS shares,
IFNULL(AVG(difficulty), 0) AS avgsharediff IFNULL(AVG(difficulty), 0) AS avgsharediff
FROM ( FROM (
@ -603,7 +646,7 @@ class Statistics extends Base {
a.username AS account, a.username AS account,
a.donate_percent AS donate_percent, a.donate_percent AS donate_percent,
a.is_anonymous AS is_anonymous, a.is_anonymous AS is_anonymous,
ROUND(IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0), 0) AS shares IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares
FROM " . $this->share->getTableName() . " AS s FROM " . $this->share->getTableName() . " AS s
LEFT JOIN " . $this->user->getTableName() . " AS a LEFT JOIN " . $this->user->getTableName() . " AS a
ON SUBSTRING_INDEX( s.username, '.', 1 ) = a.username ON SUBSTRING_INDEX( s.username, '.', 1 ) = a.username
@ -655,78 +698,24 @@ class Statistics extends Base {
* @param $account_id int account id * @param $account_id int account id
* @return data array NOT FINISHED YET * @return data array NOT FINISHED YET
**/ **/
public function getHourlyHashrateByAccount($username, $account_id=NULL) { public function getHourlyMiningStatsByAccount($account_id, $format='array', $days = 1) {
$this->debug->append("STA " . __METHOD__, 4); $this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
id, timestamp,
IFNULL(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares, FROM_UNIXTIME(timestamp, '%Y-%m-%d %H:%i') AS time,
HOUR(time) AS hour AVG(hashrate) AS hashrate,
FROM " . $this->share->getTableName() . " AVG(workers) AS workers,
WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) AVG(sharerate) AS sharerate
AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR FROM " . $this->getUserStatsTableName() . "
AND our_result = 'Y' WHERE FROM_UNIXTIME(timestamp) >= DATE_SUB(NOW(), INTERVAL $days DAY)
AND username LIKE ? AND account_id = ?
GROUP BY HOUR(time) GROUP BY DAY(FROM_UNIXTIME(timestamp)), HOUR(FROM_UNIXTIME(timestamp))");
UNION if ($this->checkStmt($stmt) && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) {
SELECT $aData = $result->fetch_all(MYSQLI_ASSOC);
share_id, if ($format == 'json') $aData = json_encode($aData);
IFNULL(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares, return $this->memcache->setCache(__FUNCTION__ . $account_id . $format, $aData);
HOUR(time) AS hour
FROM " . $this->share->getArchiveTableName() . "
WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60))
AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR
AND our_result = 'Y'
AND username LIKE ?
GROUP BY HOUR(time)");
$username = $username . ".%";
if ($this->checkStmt($stmt) && $stmt->bind_param('ss', $username, $username) && $stmt->execute() && $result = $stmt->get_result()) {
$iStartHour = date('G');
// Initilize array
for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0;
// Fill data
while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int) $this->coin->calcHashrate($row['shares'], 3600);
return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData);
}
return $this->sqlError();
}
/**
* get Hourly hashrate for the pool
* @param none
* @return data array NOT FINISHED YET
**/
public function getHourlyHashrateByPool() {
$this->debug->append("STA " . __METHOD__, 4);
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
id,
IFNULL(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares,
HOUR(s.time) AS hour
FROM " . $this->share->getTableName() . " AS s
WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60))
AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR
AND our_result = 'Y'
GROUP BY HOUR(time)
UNION
SELECT
share_id,
IFNULL(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares,
HOUR(s.time) AS hour
FROM " . $this->share->getArchiveTableName() . " AS s
WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60))
AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR
AND our_result = 'Y'
GROUP BY HOUR(time)");
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) {
$iStartHour = date('G');
// Initilize array
for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0;
// Fill data
while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int) $this->coin->calcHashrate($row['shares'], 3600);
return $this->memcache->setCache(__FUNCTION__, $aData);
} }
return $this->sqlError(); return $this->sqlError();
} }
@ -744,7 +733,7 @@ class Statistics extends Base {
if ($this->config['payout_system'] != 'pps') { if ($this->config['payout_system'] != 'pps') {
if (@$value1['valid'] > 0 && @$value2['valid'] > 0) { if (@$value1['valid'] > 0 && @$value2['valid'] > 0) {
$this->config['reward_type'] == 'fixed' ? $reward = $this->config['reward'] : $reward = $this->block->getAverageAmount(); $this->config['reward_type'] == 'fixed' ? $reward = $this->config['reward'] : $reward = $this->block->getAverageAmount();
$aEstimates['block'] = round(( (int)$value2['valid'] / (int)$value1['valid'] ) * (float)$reward, 8); $aEstimates['block'] = round(( (float)$value2['valid'] / (float)$value1['valid'] ) * (float)$reward, 8);
$bNoFees == 0 ? $aEstimates['fee'] = round(((float)$this->config['fees'] / 100) * (float)$aEstimates['block'], 8) : $aEstimates['fee'] = 0; $bNoFees == 0 ? $aEstimates['fee'] = round(((float)$this->config['fees'] / 100) * (float)$aEstimates['block'], 8) : $aEstimates['fee'] = 0;
$aEstimates['donation'] = round((( (float)$dDonate / 100) * ((float)$aEstimates['block'] - (float)$aEstimates['fee'])), 8); $aEstimates['donation'] = round((( (float)$dDonate / 100) * ((float)$aEstimates['block'] - (float)$aEstimates['fee'])), 8);
$aEstimates['payout'] = round((float)$aEstimates['block'] - (float)$aEstimates['donation'] - (float)$aEstimates['fee'], 8); $aEstimates['payout'] = round((float)$aEstimates['block'] - (float)$aEstimates['donation'] - (float)$aEstimates['fee'], 8);
@ -789,7 +778,7 @@ class Statistics extends Base {
SELECT SELECT
IFNULL(COUNT(id), 0) as count, IFNULL(COUNT(id), 0) as count,
IFNULL(AVG(difficulty), 0) as average, IFNULL(AVG(difficulty), 0) as average,
IFNULL(ROUND(SUM(shares)), 0) as shares, IFNULL(SUM(shares), 0) as shares,
IFNULL(SUM(amount), 0) as rewards IFNULL(SUM(amount), 0) as rewards
FROM " . $this->block->getTableName() . " FROM " . $this->block->getTableName() . "
WHERE FROM_UNIXTIME(time) > DATE_SUB(now(), INTERVAL ? HOUR) WHERE FROM_UNIXTIME(time) > DATE_SUB(now(), INTERVAL ? HOUR)
@ -914,6 +903,17 @@ class Statistics extends Base {
return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->total); return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->total);
return $this->sqlError(); return $this->sqlError();
} }
/**
* Purge older entries from our statistics_users table
**/
public function purgeUserStats($days = 1) {
// Fallbacks if unset
$stmt = $this->mysqli->prepare("DELETE FROM " . $this->getUserStatsTableName() . " WHERE FROM_UNIXTIME(timestamp) <= DATE_SUB(NOW(), INTERVAL ? DAY)");
if ($this->checkStmt($stmt) && $stmt->bind_param('i', $days) && $stmt->execute())
return $stmt->affected_rows;
return $this->sqlError();
}
} }
$statistics = new Statistics(); $statistics = new Statistics();

View File

@ -81,6 +81,8 @@ class Tools extends Base {
return 'cryptorush'; return 'cryptorush';
} else if (preg_match('/mintpal.com/', $url)) { } else if (preg_match('/mintpal.com/', $url)) {
return 'mintpal'; return 'mintpal';
} else if (preg_match('/bittrex.com/', $url)) {
return 'bittrex';
} }
$this->setErrorMessage("API URL unknown"); $this->setErrorMessage("API URL unknown");
return false; return false;
@ -116,6 +118,9 @@ class Tools extends Base {
case 'mintpal': case 'mintpal':
return @$aData['0']['last_price']; return @$aData['0']['last_price'];
break; break;
case 'bittrex':
return @$aData['result']['Last'];
break;
} }
} else { } else {
$this->setErrorMessage("Got an invalid response from ticker API"); $this->setErrorMessage("Got an invalid response from ticker API");

View File

@ -355,7 +355,7 @@ class Transaction extends Base {
a.id, a.id,
a.username, a.username,
a.ap_threshold, a.ap_threshold,
a.coin_address, ca.coin_address,
IFNULL( IFNULL(
ROUND( ROUND(
( (
@ -370,11 +370,13 @@ class Transaction extends Base {
ON t.block_id = b.id ON t.block_id = b.id
LEFT JOIN " . $this->user->getTableName() . " AS a LEFT JOIN " . $this->user->getTableName() . " AS a
ON t.account_id = a.id ON t.account_id = a.id
WHERE t.archived = 0 AND a.ap_threshold > 0 AND a.coin_address IS NOT NULL AND a.coin_address != '' LEFT JOIN " . $this->coin_address->getTableName() . " AS ca
ON ca.account_id = a.id
WHERE t.archived = 0 AND a.ap_threshold > 0 AND ca.coin_address IS NOT NULL AND ca.coin_address != '' AND ca.currency = ?
GROUP BY t.account_id GROUP BY t.account_id
HAVING confirmed > a.ap_threshold AND confirmed > " . $this->config['txfee_auto'] . " HAVING confirmed > a.ap_threshold AND confirmed > " . $this->config['txfee_auto'] . "
LIMIT ?"); LIMIT ?");
if ($this->checkStmt($stmt) && $stmt->bind_param('i', $limit) && $stmt->execute() && $result = $stmt->get_result()) if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_all(MYSQLI_ASSOC); return $result->fetch_all(MYSQLI_ASSOC);
return $this->sqlError(); return $this->sqlError();
} }
@ -446,7 +448,7 @@ class Transaction extends Base {
a.id, a.id,
a.username, a.username,
a.ap_threshold, a.ap_threshold,
a.coin_address, ca.coin_address,
p.id AS payout_id, p.id AS payout_id,
IFNULL( IFNULL(
ROUND( ROUND(
@ -464,11 +466,13 @@ class Transaction extends Base {
ON t.account_id = p.account_id ON t.account_id = p.account_id
LEFT JOIN " . $this->block->getTableName() . " AS b LEFT JOIN " . $this->block->getTableName() . " AS b
ON t.block_id = b.id ON t.block_id = b.id
WHERE p.completed = 0 AND t.archived = 0 AND a.coin_address IS NOT NULL AND a.coin_address != '' LEFT JOIN " . $this->coin_address->getTableName() . " AS ca
ON ca.account_id = a.id
WHERE p.completed = 0 AND t.archived = 0 AND ca.currency = ? AND ca.coin_address IS NOT NULL AND ca.coin_address != ''
GROUP BY t.account_id GROUP BY t.account_id
HAVING confirmed > " . $this->config['txfee_manual'] . " HAVING confirmed > " . $this->config['txfee_manual'] . "
LIMIT ?"); LIMIT ?");
if ($this->checkStmt($stmt) && $stmt->bind_param('i', $limit) && $stmt->execute() && $result = $stmt->get_result()) if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_all(MYSQLI_ASSOC); return $result->fetch_all(MYSQLI_ASSOC);
return $this->sqlError('E0050'); return $this->sqlError('E0050');
} }
@ -478,6 +482,7 @@ $transaction = new Transaction();
$transaction->setMemcache($memcache); $transaction->setMemcache($memcache);
$transaction->setNotification($notification); $transaction->setNotification($notification);
$transaction->setDebug($debug); $transaction->setDebug($debug);
$transaction->setCoinAddress($coin_address);
$transaction->setMysql($mysqli); $transaction->setMysql($mysqli);
$transaction->setConfig($config); $transaction->setConfig($config);
$transaction->setBlock($block); $transaction->setBlock($block);

View File

@ -163,7 +163,7 @@ class User extends Base {
$invitation->setDebug($this->debug); $invitation->setDebug($this->debug);
$invitation->setLog($this->log); $invitation->setLog($this->log);
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT COUNT(i.account_id) AS invitationcount,a.id,a.username,a.email, SELECT COUNT(i.account_id) AS invitationcount,a.id,a.username,a.email,
(SELECT COUNT(account_id) FROM " . $invitation->getTableName() . " WHERE account_id = i.account_id AND is_activated = 1 GROUP BY account_id) AS activated (SELECT COUNT(account_id) FROM " . $invitation->getTableName() . " WHERE account_id = i.account_id AND is_activated = 1 GROUP BY account_id) AS activated
FROM " . $invitation->getTableName() . " AS i FROM " . $invitation->getTableName() . " AS i
LEFT JOIN " . $this->getTableName() . " AS a LEFT JOIN " . $this->getTableName() . " AS a
@ -340,38 +340,20 @@ class User extends Base {
$this->debug->append("STA " . __METHOD__, 4); $this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
id, username, coin_address, ap_threshold a.id, a.username, ca.coin_address AS coin_address, a.ap_threshold
FROM " . $this->getTableName() . " FROM " . $this->getTableName() . " AS a
WHERE ap_threshold > 0 LEFT JOIN " . $this->coin_address->getTableName() . " AS ca
AND coin_address IS NOT NULL ON a.id = ca.account_id
WHERE ap_threshold > 0 AND ca.currency = ?
AND ca.coin_address IS NOT NULL
"); ");
if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { if ( $this->checkStmt($stmt) && $stmt->bind_param('s', $this->config['currency']) && $stmt->execute() && $result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_ASSOC); return $result->fetch_all(MYSQLI_ASSOC);
} }
$this->debug->append("Unable to fetch users with AP set"); $this->debug->append("Unable to fetch users with AP set");
return false; return false;
} }
/**
* Fetch users coin address
* @param userID int UserID
* @return data string Coin Address
**/
public function getCoinAddress($userID) {
$this->debug->append("STA " . __METHOD__, 4);
return $this->getSingle($userID, 'coin_address', 'id');
}
/**
* Check if a coin address exists already
* @param address string Coin Address
* @return bool True of false
**/
public function existsCoinAddress($address) {
$this->debug->append("STA " . __METHOD__, 4);
return $this->getSingle($address, 'coin_address', 'coin_address', 's') === $address;
}
/** /**
* Fetch users donation value * Fetch users donation value
* @param userID int UserID * @param userID int UserID
@ -514,12 +496,12 @@ class User extends Base {
$this->setErrorMessage('Donation above allowed 100% limit'); $this->setErrorMessage('Donation above allowed 100% limit');
return false; return false;
} }
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { if ($email != 'hidden' && $email != NULL && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->setErrorMessage('Invalid email address'); $this->setErrorMessage('Invalid email address');
return false; return false;
} }
if (!empty($address)) { if (!empty($address)) {
if ($address != $this->getCoinAddress($userID) && $this->existsCoinAddress($address)) { if ($address != $this->coin_address->getCoinAddress($userID) && $this->coin_address->existsCoinAddress($address)) {
$this->setErrorMessage('Address is already in use'); $this->setErrorMessage('Address is already in use');
return false; return false;
} }
@ -558,11 +540,23 @@ class User extends Base {
} }
} }
// If we hide our email or it's not set, fetch current one to update
if ($email == 'hidden' || $email == NULL)
$email = $this->getUserEmailById($userID);
// We passed all validation checks so update the account // We passed all validation checks so update the account
$stmt = $this->mysqli->prepare("UPDATE $this->table SET coin_address = ?, ap_threshold = ?, donate_percent = ?, email = ?, timezone = ?, is_anonymous = ? WHERE id = ?"); $stmt = $this->mysqli->prepare("UPDATE $this->table SET ap_threshold = ?, donate_percent = ?, email = ?, timezone = ?, is_anonymous = ? WHERE id = ?");
if ($this->checkStmt($stmt) && $stmt->bind_param('sddssii', $address, $threshold, $donate, $email, $timezone, $is_anonymous, $userID) && $stmt->execute()) { if ($this->checkStmt($stmt) && $stmt->bind_param('ddssii', $threshold, $donate, $email, $timezone, $is_anonymous, $userID) && $stmt->execute()) {
$this->log->log("info", $this->getUserName($userID)." updated their account details"); $this->log->log("info", $this->getUserName($userID)." updated their account details");
return true; // Update coin address too
if ($address) {
if ($this->coin_address->update($userID, $address)) {
return true;
}
} else {
if ($this->coin_address->remove($userID, $address)) {
return true;
}
}
} }
// Catchall // Catchall
$this->setErrorMessage('Failed to update your account'); $this->setErrorMessage('Failed to update your account');
@ -703,22 +697,18 @@ class User extends Base {
$this->debug->append("Fetching user information for user id: $userID"); $this->debug->append("Fetching user information for user id: $userID");
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
id, username, pin, api_key, is_admin, is_anonymous, email, timezone, no_fees, id AS id, username, pin, api_key, is_admin, is_anonymous, email, timezone, no_fees,
IFNULL(donate_percent, '0') as donate_percent, coin_address, ap_threshold IFNULL(donate_percent, '0') as donate_percent, ap_threshold
FROM $this->table FROM " . $this->getTableName() . "
WHERE id = ? LIMIT 0,1"); WHERE id = ? LIMIT 0,1");
if ($this->checkStmt($stmt)) { if ($this->checkStmt($stmt) && $stmt->bind_param('i', $userID) && $stmt->execute() && $result = $stmt->get_result()) {
$stmt->bind_param('i', $userID); $aData = $result->fetch_assoc();
if (!$stmt->execute()) { $aData['coin_address'] = $this->coin_address->getCoinAddress($userID);
$this->debug->append('Failed to execute statement');
return false;
}
$result = $stmt->get_result();
$stmt->close(); $stmt->close();
return $result->fetch_assoc(); return $aData;
} }
$this->debug->append("Failed to fetch user information for $userID"); $this->debug->append("Failed to fetch user information for $userID");
return false; return $this->sqlError();
} }
/** /**
@ -742,6 +732,10 @@ class User extends Base {
return false; return false;
} }
if (!is_null($coinaddress)) { if (!is_null($coinaddress)) {
if ($this->coin_address->existsCoinAddress($coinaddress)) {
$this->setErrorMessage('Coin address is already taken');
return false;
}
if (!$this->bitcoin->validateaddress($coinaddress)) { if (!$this->bitcoin->validateaddress($coinaddress)) {
$this->setErrorMessage('Coin address is not valid'); $this->setErrorMessage('Coin address is not valid');
return false; return false;
@ -755,7 +749,7 @@ class User extends Base {
$this->setErrorMessage( 'This e-mail address is already taken' ); $this->setErrorMessage( 'This e-mail address is already taken' );
return false; return false;
} }
if (strlen($password1) < 8) { if (strlen($password1) < 8) {
$this->setErrorMessage( 'Password is too short, minimum of 8 characters required' ); $this->setErrorMessage( 'Password is too short, minimum of 8 characters required' );
return false; return false;
} }
@ -801,15 +795,15 @@ class User extends Base {
! $this->setting->getValue('accounts_confirm_email_disabled') ? $is_locked = 1 : $is_locked = 0; ! $this->setting->getValue('accounts_confirm_email_disabled') ? $is_locked = 1 : $is_locked = 0;
$is_admin = 0; $is_admin = 0;
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_locked, coin_address) INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_locked)
VALUES (?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?)
"); ");
} else { } else {
$is_locked = 0; $is_locked = 0;
$is_admin = 1; $is_admin = 1;
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_admin, is_locked, coin_address) INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_admin, is_locked)
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?) VALUES (?, ?, ?, ?, ?, ?, 1, ?)
"); ");
} }
@ -820,7 +814,9 @@ class User extends Base {
$username_clean = strip_tags($username); $username_clean = strip_tags($username);
$signup_time = time(); $signup_time = time();
if ($this->checkStmt($stmt) && $stmt->bind_param('sssissis', $username_clean, $password_hash, $email1, $signup_time, $pin_hash, $apikey_hash, $is_locked, $coinaddress) && $stmt->execute()) { if ($this->checkStmt($stmt) && $stmt->bind_param('sssissi', $username_clean, $password_hash, $email1, $signup_time, $pin_hash, $apikey_hash, $is_locked) && $stmt->execute()) {
$new_account_id = $this->mysqli->insert_id;
if (!is_null($coinaddress)) $this->coin_address->add($new_account_id, $coinaddress);
if (! $this->setting->getValue('accounts_confirm_email_disabled') && $is_admin != 1) { if (! $this->setting->getValue('accounts_confirm_email_disabled') && $is_admin != 1) {
if ($token = $this->token->createToken('confirm_email', $stmt->insert_id)) { if ($token = $this->token->createToken('confirm_email', $stmt->insert_id)) {
$aData['username'] = $username_clean; $aData['username'] = $username_clean;
@ -843,7 +839,8 @@ class User extends Base {
} else { } else {
$this->setErrorMessage( 'Unable to register' ); $this->setErrorMessage( 'Unable to register' );
$this->debug->append('Failed to insert user into DB: ' . $this->mysqli->error); $this->debug->append('Failed to insert user into DB: ' . $this->mysqli->error);
if ($stmt->sqlstate == '23000') $this->setErrorMessage( 'Username, email or Coinaddress already registered' ); echo $this->mysqli->error;
if ($stmt->sqlstate == '23000') $this->setErrorMessage( 'Username or email already registered' );
return false; return false;
} }
return false; return false;
@ -997,4 +994,5 @@ $user->setMail($mail);
$user->setToken($oToken); $user->setToken($oToken);
$user->setBitcoin($bitcoin); $user->setBitcoin($bitcoin);
$user->setSetting($setting); $user->setSetting($setting);
$user->setCoinAddress($coin_address);
$user->setErrorCodes($aErrorCodes); $user->setErrorCodes($aErrorCodes);

View File

@ -160,6 +160,13 @@ $aSettings['statistics'][] = array(
'name' => 'statistics_ajax_data_interval', 'value' => $setting->getValue('statistics_ajax_data_interval'), 'name' => 'statistics_ajax_data_interval', 'value' => $setting->getValue('statistics_ajax_data_interval'),
'tooltip' => 'Time in minutes, interval for hashrate and sharerate calculations. Higher intervals allow for better accuracy at a higer server load.' 'tooltip' => 'Time in minutes, interval for hashrate and sharerate calculations. Higher intervals allow for better accuracy at a higer server load.'
); );
$aSettings['statistics'][] = array(
'display' => 'Graphing Days', 'type' => 'text',
'size' => 25,
'default' => 1,
'name' => 'statistics_graphing_days', 'value' => $setting->getValue('statistics_graphing_days'),
'tooltip' => 'How many days to graph out on the statistics -> graphs page.'
);
$aSettings['statistics'][] = array( $aSettings['statistics'][] = array(
'display' => 'Block Statistics Count', 'type' => 'text', 'display' => 'Block Statistics Count', 'type' => 'text',
'size' => 25, 'size' => 25,

View File

@ -3,15 +3,13 @@
// Small helper array that may be used on some page controllers to // Small helper array that may be used on some page controllers to
// fetch the crons we wish to monitor // fetch the crons we wish to monitor
switch ($config['payout_system']) { switch ($config['payout_system']) {
case 'pplns':
$sPayoutSystem = $config['payout_system'] . '_payout';
break;
case 'pps':
$sPayoutSystem = $config['payout_system'] . '_payout';
break;
case 'prop': case 'prop':
$sPayoutSystem = 'proportional_payout'; $sPayoutSystem = 'proportional_payout';
break; break;
default: // pps && pplns land here
$sPayoutSystem = $config['payout_system'] . '_payout';
} }
$aMonitorCrons = array('statistics','tickerupdate','notifications','tables_cleanup','findblock',$sPayoutSystem,'blockupdate','payouts'); $aMonitorCrons = array('statistics','tickerupdate','notifications','tables_cleanup','findblock',$sPayoutSystem,'blockupdate','payouts');
?>

View File

@ -108,7 +108,10 @@ class jsonRPCClient {
curl_setopt($ch, CURLOPT_USERPWD, $url['user'] . ":" . $url['pass']); curl_setopt($ch, CURLOPT_USERPWD, $url['user'] . ":" . $url['pass']);
curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request); curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch); $response = curl_exec($ch);
if (curl_errno($ch)) throw new Exception('RPC call failed: ' . curl_error($ch));
if ($this->debug) $this->debug_output[] = 'Response: ' . $response; if ($this->debug) $this->debug_output[] = 'Response: ' . $response;
$response = json_decode($response, true); $response = json_decode($response, true);
$resultStatus = curl_getinfo($ch); $resultStatus = curl_getinfo($ch);
@ -116,7 +119,6 @@ class jsonRPCClient {
if ($resultStatus['http_code'] == '401') throw new Exception('RPC call did not return 200: Authentication failed'); if ($resultStatus['http_code'] == '401') throw new Exception('RPC call did not return 200: Authentication failed');
throw new Exception('RPC call did not return 200: HTTP error: ' . $resultStatus['http_code'] . ' - JSON Response: [' . @$response['error']['code'] . '] ' . @$response['error']['message']); throw new Exception('RPC call did not return 200: HTTP error: ' . $resultStatus['http_code'] . ' - JSON Response: [' . @$response['error']['code'] . '] ' . @$response['error']['message']);
} }
if (curl_errno($ch)) throw new Exception('RPC call failed: ' . curl_error($ch));
curl_close($ch); curl_close($ch);
// final checks and return // final checks and return

View File

@ -104,7 +104,7 @@ if ($user->isAuthenticated()) {
$_SESSION['POPUP'][] = array('CONTENT' => 'You have not yet unlocked account withdrawls.', 'TYPE' => 'alert alert-danger'); $_SESSION['POPUP'][] = array('CONTENT' => 'You have not yet unlocked account withdrawls.', 'TYPE' => 'alert alert-danger');
} else if ($aBalance['confirmed'] < $config['mp_threshold']) { } else if ($aBalance['confirmed'] < $config['mp_threshold']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Payout must be greater or equal than ' . $config['mp_threshold'] . '.', 'TYPE' => 'info'); $_SESSION['POPUP'][] = array('CONTENT' => 'Payout must be greater or equal than ' . $config['mp_threshold'] . '.', 'TYPE' => 'info');
} else if (!$user->getCoinAddress($_SESSION['USERDATA']['id'])) { } else if (!$coin_address->getCoinAddress($_SESSION['USERDATA']['id'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger'); $_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger');
} else { } else {
$user->log->log("info", $_SESSION['USERDATA']['username']." requesting manual payout"); $user->log->log("info", $_SESSION['USERDATA']['username']." requesting manual payout");

View File

@ -4,12 +4,10 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
if ($user->isAuthenticated()) { if ($user->isAuthenticated()) {
if (!$user->getCoinAddress($_SESSION['USERDATA']['id']) AND $setting->getValue('disable_worker_edit')) { if (!$coin_address->getCoinAddress($_SESSION['USERDATA']['id']) AND $setting->getValue('disable_worker_edit')) {
$_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger'); $_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger');
$_SESSION['POPUP'][] = array('CONTENT' => 'You can not add workers unless a valid Payout Address is set in your User Settings.', 'TYPE' => 'alert alert-danger'); $_SESSION['POPUP'][] = array('CONTENT' => 'You can not add workers unless a valid Payout Address is set in your User Settings.', 'TYPE' => 'alert alert-danger');
$smarty->assign('CONTENT', 'disabled.tpl'); $smarty->assign('CONTENT', 'disabled.tpl');
} else { } else {
switch (@$_REQUEST['do']) { switch (@$_REQUEST['do']) {
case 'delete': case 'delete':

View File

@ -20,7 +20,7 @@ if ($setting->getValue('notifications_disable_pool_newsletter', 0) == 1) {
$iSuccess = 0; $iSuccess = 0;
foreach ($user->getAllAssoc() as $aData) { foreach ($user->getAllAssoc() as $aData) {
$aUserNotificationSettings = $notification->getNotificationSettings($aData['id']); $aUserNotificationSettings = $notification->getNotificationSettings($aData['id']);
if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1) continue; if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1 || empty($aData['email'])) continue;
$aData['subject'] = $_REQUEST['data']['subject']; $aData['subject'] = $_REQUEST['data']['subject'];
$aData['CONTENT'] = $_REQUEST['data']['content']; $aData['CONTENT'] = $_REQUEST['data']['content'];
if (!$mail->sendMail('newsletter/body', $aData, true)) { if (!$mail->sendMail('newsletter/body', $aData, true)) {

View File

@ -5,7 +5,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
$api->isActive(); $api->isActive();
// Check for valid API key // Check for valid API key
$id = $user->checkApiKey($_REQUEST['api_key']); $id = $user->checkApiKey(@$_REQUEST['api_key']);
header('HTTP/1.1 400 Bad Request'); header('HTTP/1.1 400 Bad Request');
die('400 Bad Request'); die('400 Bad Request');

View File

@ -19,7 +19,9 @@ echo json_encode(
'workers' => $worker->getCountAllActiveWorkers(), 'workers' => $worker->getCountAllActiveWorkers(),
'shares_this_round' => $aShares['valid'], 'shares_this_round' => $aShares['valid'],
'last_block' => $aLastBlock['height'], 'last_block' => $aLastBlock['height'],
'network_hashrate' => $dNetworkHashrate 'network_hashrate' => $dNetworkHashrate,
'fee' => $config['fees'],
'payout' => $config['payout_system']
) )
); );

View File

@ -52,6 +52,7 @@ if ($user->isAuthenticated()) {
$smarty->assign('BLOCKSFOUND', $aLastBlocks); $smarty->assign('BLOCKSFOUND', $aLastBlocks);
$smarty->assign('DISABLED_DASHBOARD', $setting->getValue('disable_dashboard')); $smarty->assign('DISABLED_DASHBOARD', $setting->getValue('disable_dashboard'));
$smarty->assign('DISABLED_DASHBOARD_API', $setting->getValue('disable_dashboard_api')); $smarty->assign('DISABLED_DASHBOARD_API', $setting->getValue('disable_dashboard_api'));
$smarty->assign('DISABLED_API', $setting->getValue('disable_api'));
$smarty->assign('ESTIMATES', array('shares' => $iEstShares, 'percent' => $dEstPercent)); $smarty->assign('ESTIMATES', array('shares' => $iEstShares, 'percent' => $dEstPercent));
$smarty->assign('NETWORK', array('difficulty' => $dDifficulty, 'block' => $iBlock, 'EstNextDifficulty' => $dEstNextDifficulty, 'EstTimePerBlock' => $dExpectedTimePerBlock, 'BlocksUntilDiffChange' => $iBlocksUntilDiffChange)); $smarty->assign('NETWORK', array('difficulty' => $dDifficulty, 'block' => $iBlock, 'EstNextDifficulty' => $dEstNextDifficulty, 'EstTimePerBlock' => $dExpectedTimePerBlock, 'BlocksUntilDiffChange' => $iBlocksUntilDiffChange));
$smarty->assign('INTERVAL', $interval / 60); $smarty->assign('INTERVAL', $interval / 60);

View File

@ -18,28 +18,30 @@ if ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_ena
} }
} }
if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail($_POST['username']))) { if (!empty($_POST['username']) && !empty($_POST['password'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'You are not allowed to login during maintenace.', 'TYPE' => 'info'); if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail($_POST['username']))) {
} else if (!empty($_POST['username']) && !empty($_POST['password'])) { $_SESSION['POPUP'][] = array('CONTENT' => 'You are not allowed to login during maintenace.', 'TYPE' => 'alert alert-info');
// Check if recaptcha is enabled, process form data if valid } else {
if (!$setting->getValue('recaptcha_enabled') || !$setting->getValue('recaptcha_enabled_logins') || ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins') && $rsp->is_valid)) { // Check if recaptcha is enabled, process form data if valid
if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { if (!$setting->getValue('recaptcha_enabled') || !$setting->getValue('recaptcha_enabled_logins') || ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins') && $rsp->is_valid)) {
// check if login is correct if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) {
if ($user->checkLogin(@$_POST['username'], @$_POST['password']) ) { // check if login is correct
$port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); if ($user->checkLogin(@$_POST['username'], @$_POST['password']) ) {
$location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]);
$location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://';
$location.= '?page=dashboard'; $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME'];
if (!headers_sent()) header('Location: ' . $location); $location.= '?page=dashboard';
exit('<meta http-equiv="refresh" content="0; url=' . htmlspecialchars($location) . '"/>'); if (!headers_sent()) header('Location: ' . $location);
exit('<meta http-equiv="refresh" content="0; url=' . htmlspecialchars($location) . '"/>');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '.$user->getError(), 'TYPE' => 'alert alert-danger');
}
} else { } else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '.$user->getError(), 'TYPE' => 'alert alert-danger'); $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning');
} }
} else { } else {
$_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger');
} }
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger');
} }
} }
// Load login template // Load login template

View File

@ -4,11 +4,9 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { if (!$smarty->isCached('master.tpl', $smarty_cache_key)) {
$debug->append('No cached version available, fetching from backend', 3); $debug->append('No cached version available, fetching from backend', 3);
if ($user->isAuthenticated()) { if ($user->isAuthenticated()) {
$aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']); $aHourlyMiningStats = $statistics->getHourlyMiningStatsByAccount($_SESSION['USERDATA']['id'], 'json', $setting->getValue('statistics_graphing_days', 1));
$aPoolHourlyHashRates = $statistics->getHourlyHashrateByPool();
} }
$smarty->assign("YOURHASHRATES", @$aHourlyHashRates); $smarty->assign('YOURMININGSTATS', @$aHourlyMiningStats);
$smarty->assign("POOLHASHRATES", @$aPoolHourlyHashRates);
} else { } else {
$debug->append('Using cached page', 3); $debug->append('Using cached page', 3);
} }

View File

@ -66,6 +66,7 @@ $aGlobal = array(
'coinaddresscheck' => $config['check_valid_coinaddress'], 'coinaddresscheck' => $config['check_valid_coinaddress'],
'csrf' => $config['csrf'], 'csrf' => $config['csrf'],
'config' => array( 'config' => array(
'sharediffprecision' => $coin->getShareDifficultyPrecision(),
'date' => $setting->getValue('system_date_format', '%m/%d/%Y %H:%M:%S'), 'date' => $setting->getValue('system_date_format', '%m/%d/%Y %H:%M:%S'),
'website_design' => $setting->getValue('website_design'), 'website_design' => $setting->getValue('website_design'),
'poolnav_enabled' => $setting->getValue('poolnav_enabled'), 'poolnav_enabled' => $setting->getValue('poolnav_enabled'),

View File

@ -2,7 +2,7 @@
$defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
define('MPOS_VERSION', '0.0.4'); define('MPOS_VERSION', '0.0.4');
define('DB_VERSION', '0.0.11'); define('DB_VERSION', '0.0.14');
define('CONFIG_VERSION', '0.0.8'); define('CONFIG_VERSION', '0.0.8');
define('HASH_VERSION', 1); define('HASH_VERSION', 1);

19
scripts/test_email.php Executable file
View File

@ -0,0 +1,19 @@
<?php
// Change to working directory
chdir(dirname(__FILE__));
// Include all settings and classes
require_once('shared.inc.php');
// Send email
$aMailData = array(
'email' => $setting->getValue('system_error_email'),
'subject' => 'Test email from mining pool',
'coinname' => $config['gettingstarted']['coinname'],
'stratumurl' => $config['gettingstarted']['stratumurl'],
'stratumport' => $config['gettingstarted']['stratumport']
);
if (!$mail->sendMail('notifications/test_email', $aMailData))
echo "Failed to send test email" . PHP_EOL;

View File

@ -42,6 +42,7 @@ echo 'Validating all coin addresses. This may take some time.' . PHP_EOL . PHP_E
printf($mask, 'Username', 'E-Mail', 'Address', 'Status'); printf($mask, 'Username', 'E-Mail', 'Address', 'Status');
foreach ($users as $aData) { foreach ($users as $aData) {
$aData['coin_address'] = $coin_address->getCoinAddress($aData['id']);
if (empty($aData['coin_address']) && $aData['is_locked'] == 0) { if (empty($aData['coin_address']) && $aData['is_locked'] == 0) {
$status = 'UNSET'; $status = 'UNSET';
} else if ($aData['is_locked'] == 1) { } else if ($aData['is_locked'] == 1) {

View File

@ -36,7 +36,6 @@
$username = $user['username']; $username = $user['username'];
$loggedIp = $user['loggedIp']; $loggedIp = $user['loggedIp'];
$lastLogin = $user['last_login']; $lastLogin = $user['last_login'];
$coinAddress = $user['coin_address'];
$mailAddress = $user['email']; $mailAddress = $user['email'];
$everLoggedIn = !empty($lastLogin); $everLoggedIn = !empty($lastLogin);

View File

@ -53,6 +53,16 @@ CREATE TABLE IF NOT EXISTS `blocks` (
KEY `time` (`time`) KEY `time` (`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Discovered blocks persisted from Litecoin Service'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Discovered blocks persisted from Litecoin Service';
CREATE TABLE IF NOT EXISTS `coin_addresses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int(11) NOT NULL,
`currency` varchar(5) NOT NULL,
`coin_address` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `coin_address` (`coin_address`),
KEY `account_id` (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `invitations` ( CREATE TABLE IF NOT EXISTS `invitations` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT, `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`account_id` int(11) unsigned NOT NULL, `account_id` int(11) unsigned NOT NULL,
@ -134,7 +144,7 @@ CREATE TABLE IF NOT EXISTS `settings` (
UNIQUE KEY `setting` (`name`) UNIQUE KEY `setting` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `settings` (`name`, `value`) VALUES ('DB_VERSION', '0.0.11'); INSERT INTO `settings` (`name`, `value`) VALUES ('DB_VERSION', '0.0.13');
CREATE TABLE IF NOT EXISTS `shares` ( CREATE TABLE IF NOT EXISTS `shares` (
`id` bigint(30) NOT NULL AUTO_INCREMENT, `id` bigint(30) NOT NULL AUTO_INCREMENT,
@ -229,12 +239,15 @@ CREATE TABLE IF NOT EXISTS `transactions` (
KEY `account_id_archived` (`account_id`,`archived`) KEY `account_id_archived` (`account_id`,`archived`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `templates` ( CREATE TABLE `statistics_users` (
`template` varchar(255) NOT NULL, `id` int(11) NOT NULL AUTO_INCREMENT,
`active` tinyint(1) NOT NULL DEFAULT 0, `account_id` int(11) NOT NULL,
`content` mediumtext, `hashrate` int(11) NOT NULL,
`modified_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `workers` int(11) NOT NULL,
PRIMARY KEY (`template`) `sharerate` float NOT NULL,
`timestamp` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `account_id_timestamp` (`account_id`,`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

View File

@ -7,7 +7,7 @@
<div class="panel-body"> <div class="panel-body">
<ul> <ul>
<li><b><i>Q: When will I get paid?</b></i></li> <li><b><i>Q: When will I get paid?</b></i></li>
&nbsp;<b>A:</b> This pool uses the follwing payout system.<br> &nbsp;<b>A:</b> This pool uses the following payout system.<br>
{if $GLOBAL.config.payout_system == 'prop'} {if $GLOBAL.config.payout_system == 'prop'}
<br> <br>
<b>Proportional (Prop)</b> - The block reward is distributed among miners in proportion to the number of shares they submitted in a round. The expected reward per share depends on the number of shares already submitted in the round. <b>Proportional (Prop)</b> - The block reward is distributed among miners in proportion to the number of shares they submitted in a round. The expected reward per share depends on the number of shares already submitted in the round.

View File

@ -28,7 +28,7 @@
{/if} {/if}
<div class="form-group"> <div class="form-group">
<label>E-Mail</label> <label>E-Mail</label>
{nocache}<input class="form-control" type="text" name="email" value="{$GLOBAL.userdata.email|escape}" size="20" {if $GLOBAL.twofactor.enabled && $GLOBAL.twofactor.options.details && !$DETAILSUNLOCKED}id="disabledInput" disabled{/if}/>{/nocache} {nocache}<input class="form-control" type="text" name="email" value="hidden" size="20" {if $GLOBAL.twofactor.enabled && $GLOBAL.twofactor.options.details && !$DETAILSUNLOCKED}id="disabledInput" disabled{/if}/>{/nocache}
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Timezone</label> <label>Timezone</label>

View File

@ -4,7 +4,7 @@
{literal} {literal}
$(document).ready(function(){ $(document).ready(function(){
$('#qrcodeholder').qrcode({ $('#qrcodeholder').qrcode({
text : "{/literal}|http{if $smarty.server.HTTPS|default:"0" eq 'on'}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=api|{$GLOBAL.userdata.api_key}|{$GLOBAL.userdata.id}|{$GLOBAL.config.currency|upper}|{literal}", text : "{/literal}|http{if $smarty.server.HTTPS|default:"0" eq 'on'}s{/if}://{$smarty.server.SERVER_NAME}{if $smarty.server.SERVER_PORT != "443" && $smarty.server.SERVER_PORT != "80"}:{$smarty.server.SERVER_PORT}{/if}{$smarty.server.SCRIPT_NAME}?page=api|{$GLOBAL.userdata.api_key}|{$GLOBAL.userdata.id}|{$GLOBAL.config.currency|upper}|{literal}",
render : "canvas", // 'canvas' or 'table'. Default value is 'canvas' render : "canvas", // 'canvas' or 'table'. Default value is 'canvas'
background : "#ffffff", background : "#ffffff",
foreground : "#000000", foreground : "#000000",

View File

@ -16,7 +16,9 @@
{include file="dashboard/overview/default.tpl"} {include file="dashboard/overview/default.tpl"}
{include file="dashboard/round_statistics/$PAYOUT_SYSTEM/default.tpl"} {include file="dashboard/round_statistics/$PAYOUT_SYSTEM/default.tpl"}
{include file="dashboard/account_data/default.tpl"} {include file="dashboard/account_data/default.tpl"}
{if !$DISABLED_API}
{include file="dashboard/worker_information/default.tpl"} {include file="dashboard/worker_information/default.tpl"}
{/if}
{include file="dashboard/blocks/default.tpl"} {include file="dashboard/blocks/default.tpl"}
</div> </div>
</div> </div>

View File

@ -108,15 +108,15 @@ $(document).ready(function(){
$('#b-nethashrate').html('n/a'); $('#b-nethashrate').html('n/a');
} }
$('#b-sharerate').html((parseFloat(data.getdashboarddata.data.personal.sharerate).toFixed(2))); $('#b-sharerate').html((parseFloat(data.getdashboarddata.data.personal.sharerate).toFixed(2)));
$('#b-yvalid').html(number_format(data.getdashboarddata.data.personal.shares.valid)); $('#b-yvalid').html(number_format(data.getdashboarddata.data.personal.shares.valid, {/literal}{$GLOBAL.config.sharediffprecision}{literal}));
$('#b-yivalid').html(number_format(data.getdashboarddata.data.personal.shares.invalid)); $('#b-yivalid').html(number_format(data.getdashboarddata.data.personal.shares.invalid, {/literal}{$GLOBAL.config.sharediffprecision}{literal}));
if ( data.getdashboarddata.data.personal.shares.valid > 0 ) { if ( data.getdashboarddata.data.personal.shares.valid > 0 ) {
$('#b-yefficiency').html(number_format(100 - data.getdashboarddata.data.personal.shares.invalid_percent, 2) + "%"); $('#b-yefficiency').html(number_format(100 - data.getdashboarddata.data.personal.shares.invalid_percent, 2) + "%");
} else { } else {
$('#b-yefficiency').html(number_format(0, 2) + "%"); $('#b-yefficiency').html(number_format(0, 2) + "%");
} }
$('#b-pvalid').html(number_format(data.getdashboarddata.data.pool.shares.valid)); $('#b-pvalid').html(number_format(data.getdashboarddata.data.pool.shares.valid, {/literal}{$GLOBAL.config.sharediffprecision}{literal}));
$('#b-pivalid').html(number_format(data.getdashboarddata.data.pool.shares.invalid)); $('#b-pivalid').html(number_format(data.getdashboarddata.data.pool.shares.invalid, {/literal}{$GLOBAL.config.sharediffprecision}{literal}));
if ( data.getdashboarddata.data.pool.shares.valid > 0 ) { if ( data.getdashboarddata.data.pool.shares.valid > 0 ) {
$('#b-pefficiency').html(number_format(100 - data.getdashboarddata.data.pool.shares.invalid_percent, 2) + "%"); $('#b-pefficiency').html(number_format(100 - data.getdashboarddata.data.pool.shares.invalid_percent, 2) + "%");
} else { } else {
@ -178,7 +178,7 @@ $(document).ready(function(){
return; return;
} }
if (blocks[0].height > lastBlock) { if (blocks[0].height > lastBlock) {
if(canCreateSoundJS) { if(canCreateSoundJS) {
createjs.Sound.play('ding'); createjs.Sound.play('ding');
} }
lastBlock = blocks[0].height; lastBlock = blocks[0].height;
@ -234,6 +234,7 @@ $(document).ready(function(){
}); });
})(); })();
{/literal}{if !$DISABLED_API}{literal}
// Worker process to update active workers in the account details table // Worker process to update active workers in the account details table
(function worker2() { (function worker2() {
$.ajax({ $.ajax({
@ -250,7 +251,9 @@ $(document).ready(function(){
} }
}); });
})(); })();
{/literal}{/if}{literal}
{/literal}{if !$DISABLED_API}{literal}
// Worker process to update user account balances // Worker process to update user account balances
// Our worker process to keep worker information updated // Our worker process to keep worker information updated
(function worker3() { (function worker3() {
@ -265,7 +268,8 @@ $(document).ready(function(){
} }
}); });
})(); })();
{/literal}{/if}{literal}
// Mute Button // Mute Button
$('#muteButton').click(function(){ $('#muteButton').click(function(){
if(muteFlag == 2) { if(muteFlag == 2) {
@ -280,8 +284,6 @@ $(document).ready(function(){
$(this).find($(".fa")).removeClass('fa-volume-up').addClass('fa-volume-off'); $(this).find($(".fa")).removeClass('fa-volume-up').addClass('fa-volume-off');
} }
}); });
}); });
{/literal} {/literal}
</script> </script>

View File

@ -9,12 +9,12 @@
<th><h5><i class="fa fa-smile-o fa-fw"></i> Valid</h5></th> <th><h5><i class="fa fa-smile-o fa-fw"></i> Valid</h5></th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-yvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.valid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.valid|number_format}</div> <div id="b-yvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.valid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.valid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-pvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.valid|number_format}" role="progressbar">{$GLOBAL.roundshares.valid|number_format}</div> <div id="b-pvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.valid|number_format}" role="progressbar">{$GLOBAL.roundshares.valid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
</tr> </tr>
@ -22,12 +22,12 @@
<th><h5><i class="fa fa-frown-o fa-fw"></i> Invalid</h5></th> <th><h5><i class="fa fa-frown-o fa-fw"></i> Invalid</h5></th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-yivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.invalid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.invalid|number_format}</div> <div id="b-yivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.invalid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.invalid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-pivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.invalid|number_format}" role="progressbar">{$GLOBAL.roundshares.invalid|number_format}</div> <div id="b-pivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.invalid|number_format}" role="progressbar">{$GLOBAL.roundshares.invalid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
</tr> </tr>

View File

@ -9,12 +9,12 @@
<th><h5><i class="fa fa-smile-o fa-fw"></i> Valid</h6></th> <th><h5><i class="fa fa-smile-o fa-fw"></i> Valid</h6></th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-yvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.valid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.valid|number_format}</div> <div id="b-yvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.valid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.valid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-pvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.valid|number_format}" role="progressbar">{$GLOBAL.roundshares.valid|number_format}</div> <div id="b-pvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.valid|number_format}" role="progressbar">{$GLOBAL.roundshares.valid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
</tr> </tr>
@ -22,12 +22,12 @@
<th><h5><i class="fa fa-frown-o fa-fw"></i> Invalid</h6></th> <th><h5><i class="fa fa-frown-o fa-fw"></i> Invalid</h6></th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-yivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.invalid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.invalid|number_format}</div> <div id="b-yivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.invalid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.invalid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-pivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.invalid|number_format}" role="progressbar">{$GLOBAL.roundshares.invalid|number_format}</div> <div id="b-pivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.invalid|number_format}" role="progressbar">{$GLOBAL.roundshares.invalid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
</tr> </tr>

View File

@ -9,12 +9,12 @@
<th><h5><i class="fa fa-smile-o fa-fw"></i> Valid</h5></th> <th><h5><i class="fa fa-smile-o fa-fw"></i> Valid</h5></th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-yvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.valid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.valid|number_format}</div> <div id="b-yvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.valid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.valid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-pvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.valid|number_format}" role="progressbar">{$GLOBAL.roundshares.valid|number_format}</div> <div id="b-pvalid" class="progress-bar progress-bar-success black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.valid|number_format}" role="progressbar">{$GLOBAL.roundshares.valid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
</tr> </tr>
@ -22,12 +22,12 @@
<th><h5><i class="fa fa-frown-o fa-fw"></i> Invalid</h5></th> <th><h5><i class="fa fa-frown-o fa-fw"></i> Invalid</h5></th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-yivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.invalid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.invalid|number_format}</div> <div id="b-yivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.userdata.shares.invalid|number_format}" role="progressbar">{$GLOBAL.userdata.shares.invalid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
<th> <th>
<div class="progress progress-striped progress-fix"> <div class="progress progress-striped progress-fix">
<div id="b-pivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.invalid|number_format}" role="progressbar">{$GLOBAL.roundshares.invalid|number_format}</div> <div id="b-pivalid" class="progress-bar progress-bar-danger black" style="width: 100%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="{$GLOBAL.roundshares.invalid|number_format}" role="progressbar">{$GLOBAL.roundshares.invalid|number_format:$GLOBAL.config.sharediffprecision}</div>
</div> </div>
</th> </th>
</tr> </tr>

View File

@ -1,39 +1,46 @@
<article class="module width_half"> <div class="row">
<form action="{$smarty.server.SCRIPT_NAME}" method="post"> <form class="col-md-4" role="form" method="POST">
<input type="hidden" name="token" value="{$smarty.request.token|escape}"> <input type="hidden" name="token" value="{$smarty.request.token|escape}">
<input type="hidden" name="page" value="{$smarty.request.page|escape}"> <input type="hidden" name="page" value="{$smarty.request.page|escape}">
<input type="hidden" name="action" value="{$smarty.request.action|escape}"> <input type="hidden" name="action" value="{$smarty.request.action|escape}">
<input type="hidden" name="ctoken" value="{$CTOKEN|escape|default:""}" /> <input type="hidden" name="ctoken" value="{$CTOKEN|escape|default:""}" />
<input type="hidden" name="do" value="resetPassword"> <input type="hidden" name="do" value="resetPassword">
<header><h3>Password reset</h3></header> <div class="panel panel-default">
<div class="module_content"> <div class="panel-heading">
<fieldset> <h3 class="panel-title">Password reset</h3>
<label>New Password</label> </div>
<input type="password" name="newPassword" required> <div class="panel-body">
</fieldset> <div class="form-group">
<fieldset> <fieldset>
<label>Repeat New Password</label> <label>New Password</label>
<input type="password" name="newPassword2" required> <input class="form-control" type="password" name="newPassword" required>
</fieldset> </fieldset>
<div class="clear"></div> </div>
</div> <div class="form-group">
<footer> <fieldset>
{nocache} <label>Repeat New Password</label>
<input type="hidden" name="cp_token" value="{$smarty.request.cp_token|escape|default:""}"> <input class="form-control" type="password" name="newPassword2" required>
<input type="hidden" name="utype" value="change_pw"> </fieldset>
{if $GLOBAL.twofactor.enabled && $GLOBAL.twofactor.options.changepw} </div>
{if $CHANGEPASSSENT == 1 && $CHANGEPASSUNLOCKED == 1} </div>
<input type="submit" value="Change Password" class="btn btn-warning btn-sm"> <div class="panel-footer">
{elseif $CHANGEPASSSENT == 0 && $CHANGEPASSUNLOCKED == 1 || $CHANGEPASSSENT == 1 && $CHANGEPASSUNLOCKED == 0} {nocache}
<input type="submit" value="Change Password" class="btn btn-warning btn-sm" disabled="disabled"> <input type="hidden" name="cp_token" value="{$smarty.request.cp_token|escape|default:""}">
{elseif $CHANGEPASSSENT == 0 && $CHANGEPASSUNLOCKED == 0} <input type="hidden" name="utype" value="change_pw">
<input type="submit" value="Unlock" class="btn btn-warning btn-sm" name="unlock"> {if $GLOBAL.twofactor.enabled && $GLOBAL.twofactor.options.changepw}
{if $CHANGEPASSSENT == 1 && $CHANGEPASSUNLOCKED == 1}
<input type="submit" value="Change Password" class="btn btn-warning btn-sm">
{elseif $CHANGEPASSSENT == 0 && $CHANGEPASSUNLOCKED == 1 || $CHANGEPASSSENT == 1 && $CHANGEPASSUNLOCKED == 0}
<input type="submit" value="Change Password" class="btn btn-warning btn-sm" disabled="disabled">
{elseif $CHANGEPASSSENT == 0 && $CHANGEPASSUNLOCKED == 0}
<input type="submit" value="Unlock" class="btn btn-warning btn-sm" name="unlock">
{/if}
{else}
<input type="submit" value="Change Password" class="btn btn-warning btn-sm">
{/if} {/if}
{else} {/nocache}
<input type="submit" value="Change Password" class="btn btn-warning btn-sm"> </div>
{/if} </div>
{/nocache}
</footer>
</form> </form>
</article> </div>

View File

@ -1,10 +0,0 @@
{if is_array($YOURHASHRATES) && is_array($POOLHASHRATES)}
<div class="tab-pane fade in" id="both">
<div class="panel-heading">
Your vs. Pool Hashrate
</div>
<div class="panel-body">
<div id="both-area-chart"></div>
</div>
</div>
{/if}

View File

@ -1,95 +1,48 @@
<script> <script>
$(function () { $(function () {
var hashChart = Morris.Line({
element: 'hashrate-area-chart',
data: {$YOURMININGSTATS},
xkey: 'time',
ykeys: ['hashrate'],
labels: ['Hashrate'],
pointSize: 1,
hideHover: 'auto',
resize: true,
fillOpacity: 1.00,
lineColors: ['#24A665'],
pointFillColors: ['#24A665'],
pointStrokeColors: ['#24A665']
});
// needed for automatic activation of first tab var workersChart = Morris.Line({
$(function () { element: 'workers-area-chart',
$('#hashrategraph a:first').tab('show') data: {$YOURMININGSTATS},
}) xkey: 'time',
ykeys: ['workers'],
labels: ['Workers'],
pointSize: 1,
hideHover: 'auto',
resize: true,
fillOpacity: 1.00,
lineColors: ['#24A665'],
pointFillColors: ['#24A665'],
pointStrokeColors: ['#24A665']
});
// You can't draw here chart directly, because it's on hidden tab, instead let's do the workaround var shareCharts= Morris.Line({
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { element: 'sharerate-area-chart',
// this ain't pretty, but you should get the idea data: {$YOURMININGSTATS},
if ($(e.target).attr('href') == '#pool' && $('#pool-area-chart').html().length == 0) { xkey: 'time',
Morris.Area({ ykeys: ['sharerate'],
element: 'pool-area-chart', labels: ['Sharerate'],
data: [ pointSize: 1,
{foreach $POOLHASHRATES as $hour=>$hashrate} hideHover: 'auto',
{ resize: true,
period: '{$hour|default:"0"}:00', fillOpacity: 1.00,
Pool: '{$hashrate|default:"0"}', lineColors: ['#24A665'],
}, pointFillColors: ['#24A665'],
{/foreach} pointStrokeColors: ['#24A665']
],
parseTime: false,
behaveLikeLine: true,
xkey: 'period',
ykeys: ['Pool'],
labels: ['Hashrate'],
pointSize: 2,
hideHover: 'auto',
lineColors: ['#0b62a4'],
pointFillColors: ['#FFFFFF'],
resize: true,
fillOpacity: 1.00,
postUnits: ' KH/s'
});
}
if ($(e.target).attr('href') == '#mine' && $('#mine-area-chart').html().length == 0) {
Morris.Area({
element: 'mine-area-chart',
data: [
{foreach $YOURHASHRATES as $yourhour=>$yourhashrate}
{
period: '{$yourhour|default:"0"}:00',
Mine: '{$yourhashrate|default:"0"}',
},
{/foreach}
],
parseTime: false,
behaveLikeLine: true,
xkey: 'period',
ykeys: ['Mine'],
labels: ['Hashrate'],
pointSize: 2,
hideHover: 'auto',
lineColors: ['#24A665'],
pointFillColors: ['#FFFFFF'],
resize: true,
fillOpacity: 1.00,
postUnits: ' KH/s'
});
}
if ($(e.target).attr('href') == '#both' && $('#both-area-chart').html().length == 0) {
Morris.Area({
element: 'both-area-chart',
data: [
{foreach $YOURHASHRATES as $yourhour=>$yourhashrate}
{
period: '{$yourhour|default:"0"}:00',
Mine: '{$yourhashrate|default:"0"}',
{foreach $POOLHASHRATES as $poolhour=>$poolhashrate}
{if $yourhour eq $poolhour}
Pool: '{$poolhashrate|default:"0"}',
{/if}
{/foreach}
},
{/foreach}
],
parseTime: false,
behaveLikeLine: true,
xkey: 'period',
ykeys: ['Mine', 'Pool'],
labels: ['Your Hashrate', 'Pool Hashrate'],
pointSize: 2,
hideHover: 'auto',
resize: true,
fillOpacity: 0.1,
postUnits: ' KH/s'
});
}
}); });
}); });
</script> </script>
@ -98,19 +51,45 @@ $(function () {
<div class="col-lg-12"> <div class="col-lg-12">
<div class="panel panel-info"> <div class="panel panel-info">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-signal fa-fw"></i> Stats <i class="fa fa-signal fa-fw"></i> Average Hashrate past 24h
</div> </div>
<div class="panel-body"> <div class="panel-body">
<ul class="nav nav-pills" id="hashrategraph"> <div id="hashrate-area-chart"></div>
<li><a href="#mine" data-toggle="tab">Mine</a></li> </div>
<li><a href="#pool" data-toggle="tab">Pool</a></li> <div class="panel-footer">
<li><a href="#both" data-toggle="tab">Both</a></li> Your average hashrate per hour, updated every backend cron run.
</ul> </div>
<div class="tab-content"> </div>
{include file="{$smarty.request.page|escape}/{$smarty.request.action|escape}/mine.tpl"} </div>
{include file="{$smarty.request.page|escape}/{$smarty.request.action|escape}/pool.tpl"} </div>
{include file="{$smarty.request.page|escape}/{$smarty.request.action|escape}/both.tpl"}
</div> <div class="row">
<div class="col-lg-12">
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-signal fa-fw"></i> Average Workers past 24h
</div>
<div class="panel-body">
<div id="workers-area-chart"></div>
</div>
<div class="panel-footer">
Your average active workers per hour, updated every backend cron run.
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-signal fa-fw"></i> Average Sharerate past 24h
</div>
<div class="panel-body">
<div id="sharerate-area-chart"></div>
</div>
<div class="panel-footer">
Your share rate per hour, updated every backend cron run.
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,10 +0,0 @@
{if is_array($YOURHASHRATES)}
<div class="tab-pane fade in" id="mine">
<div class="panel-heading">
Your Hashrate
</div>
<div class="panel-body">
<div id="mine-area-chart"></div>
</div>
</div>
{/if}

View File

@ -1,10 +0,0 @@
{if is_array($POOLHASHRATES)}
<div class="tab-pane fade in" id="pool">
<div class="panel-heading">
Pool Hashrate
</div>
<div class="panel-body">
<div id="pool-area-chart"></div>
</div>
</div>
{/if}

View File

@ -2,7 +2,7 @@
<body> <body>
<p>Hello valued miner,</p><br /> <p>Hello valued miner,</p><br />
<p>{nocache}{$DATA.username}{/nocache} invited you to participate on this pool: <p>{nocache}{$DATA.username}{/nocache} invited you to participate on this pool:
<p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=register&token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=register&token={nocache}{$DATA.token}{/nocache}</a></p> <p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{if $smarty.server.SERVER_PORT != "443" && $smarty.server.SERVER_PORT != "80"}:{$smarty.server.SERVER_PORT}{/if}{$smarty.server.SCRIPT_NAME}?page=register&token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=register&token={nocache}{$DATA.token}{/nocache}</a></p>
{if $DATA.message}<p>Personal message:</p><p>{nocache}{$DATA.message}{/nocache}</p>{/if} {if $DATA.message}<p>Personal message:</p><p>{nocache}{$DATA.message}{/nocache}</p>{/if}
<p></p> <p></p>
<p>Cheers,</p> <p>Cheers,</p>

View File

@ -2,7 +2,7 @@
<body> <body>
<p>You have a pending request to change your account details.</p> <p>You have a pending request to change your account details.</p>
<p>If you initiated this request, please follow the link below to confirm your changes. If you did NOT, please notify an administrator.</p> <p>If you initiated this request, please follow the link below to confirm your changes. If you did NOT, please notify an administrator.</p>
<p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&ea_token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&ea_token={nocache}{$DATA.token}{/nocache}</a></p> <p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{if $smarty.server.SERVER_PORT != "443" && $smarty.server.SERVER_PORT != "80"}:{$smarty.server.SERVER_PORT}{/if}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&ea_token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&ea_token={nocache}{$DATA.token}{/nocache}</a></p>
<br/> <br/>
<br/> <br/>
</body> </body>

View File

@ -2,7 +2,7 @@
<body> <body>
<p>You have a pending request to change your password.</p> <p>You have a pending request to change your password.</p>
<p>If you initiated this request, please follow the link below to confirm your changes. If you did NOT, please notify an administrator.</p> <p>If you initiated this request, please follow the link below to confirm your changes. If you did NOT, please notify an administrator.</p>
<p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&cp_token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&cp_token={nocache}{$DATA.token}{/nocache}</a></p> <p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{if $smarty.server.SERVER_PORT != "443" && $smarty.server.SERVER_PORT != "80"}:{$smarty.server.SERVER_PORT}{/if}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&cp_token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&cp_token={nocache}{$DATA.token}{/nocache}</a></p>
<br/> <br/>
<br/> <br/>
</body> </body>

View File

@ -1,7 +1,7 @@
<html> <html>
<body> <body>
<p>You account has been locked due to too many failed password or PIN attempts. Please follow the URL below to unlock your account.</p> <p>You account has been locked due to too many failed password or PIN attempts. Please follow the URL below to unlock your account.</p>
<p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=unlock&token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=unlock&token={nocache}{$DATA.token}{/nocache}</a></p> <p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{if $smarty.server.SERVER_PORT != "443" && $smarty.server.SERVER_PORT != "80"}:{$smarty.server.SERVER_PORT}{/if}{$smarty.server.SCRIPT_NAME}?page=account&action=unlock&token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=unlock&token={nocache}{$DATA.token}{/nocache}</a></p>
<br/> <br/>
<br/> <br/>
</body> </body>

View File

@ -0,0 +1,6 @@
{include file="../global/header.tpl"}
<h1>Test email</h1>
<p>If you see this email - your email protocol is configured correctly</p>
<p>Coin name: {$DATA.coinname}</p>
<p>Stratum: {$DATA.stratumurl}:{$DATA.stratumport}</p>
{include file="../global/footer.tpl"}

View File

@ -2,7 +2,7 @@
<body> <body>
<p>Hello {nocache}{$DATA.username}{/nocache},</p><br /> <p>Hello {nocache}{$DATA.username}{/nocache},</p><br />
<p>You have requested a password reset through our online form. In order to complete the request please follow this link:</p> <p>You have requested a password reset through our online form. In order to complete the request please follow this link:</p>
<p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=password&action=change&token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=password&action=change&token={nocache}{$DATA.token}{/nocache}</a></p> <p><a href="http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{if $smarty.server.SERVER_PORT != "443" && $smarty.server.SERVER_PORT != "80"}:{$smarty.server.SERVER_PORT}{/if}{$smarty.server.SCRIPT_NAME}?page=password&action=change&token={nocache}{$DATA.token}{/nocache}">http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=password&action=change&token={nocache}{$DATA.token}{/nocache}</a></p>
<p>You will be asked to change your password. You can then use this new password to login to your account.</p> <p>You will be asked to change your password. You can then use this new password to login to your account.</p>
<p>Cheers,</p> <p>Cheers,</p>
<p>{$WEBSITENAME}</p> <p>{$WEBSITENAME}</p>

View File

@ -0,0 +1,32 @@
<?php
function run_0012() {
// Ugly but haven't found a better way
global $setting, $config, $user, $mysqli;
// Version information
$db_version_old = '0.0.11'; // What version do we expect
$db_version_new = '0.0.12'; // What is the new version we wish to upgrade to
$db_version_now = $setting->getValue('DB_VERSION'); // Our actual version installed
// Upgrade specific variables
$aSql[] = "CREATE TABLE `coin_addresses` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account_id` int(11) NOT NULL, `currency` varchar(5) NOT NULL, `coin_address` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `coin_address` (`coin_address`), KEY `account_id` (`account_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
$aSql[] = "INSERT IGNORE INTO coin_addresses (account_id, currency, coin_address) SELECT id, '" . $config['currency'] . "', coin_address FROM " . $user->getTableName() . " WHERE coin_address IS NOT NULL";
$aSql[] = "ALTER TABLE `" . $user->getTableName() . "` DROP `coin_address`";
$aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.12' WHERE name = 'DB_VERSION'";
if ($db_version_now == $db_version_old && version_compare($db_version_now, DB_VERSION, '<')) {
// Run the upgrade
echo '- Starting database migration to version ' . $db_version_new . PHP_EOL;
foreach ($aSql as $sql) {
echo '- Preparing: ' . $sql . PHP_EOL;
$stmt = $mysqli->prepare($sql);
if ($stmt && $stmt->execute()) {
echo '- success' . PHP_EOL;
} else {
echo '- failed: ' . $mysqli->error . PHP_EOL;
exit(1);
}
}
}
}
?>

View File

@ -0,0 +1,39 @@
<?php
function run_0013() {
// Ugly but haven't found a better way
global $setting, $config, $user, $mysqli;
// Version information
$db_version_old = '0.0.12'; // What version do we expect
$db_version_new = '0.0.13'; // What is the new version we wish to upgrade to
$db_version_now = $setting->getValue('DB_VERSION'); // Our actual version installed
// Upgrade specific variables
$aSql[] = "CREATE TABLE `statistics_users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int(11) NOT NULL,
`hashrate` int(11) NOT NULL,
`workers` int(11) NOT NULL,
`sharerate` float NOT NULL,
`timestamp` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `account_id_timestamp` (`account_id`,`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8";
$aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.13' WHERE name = 'DB_VERSION'";
if ($db_version_now == $db_version_old && version_compare($db_version_now, DB_VERSION, '<')) {
// Run the upgrade
echo '- Starting database migration to version ' . $db_version_new . PHP_EOL;
foreach ($aSql as $sql) {
echo '- Preparing: ' . $sql . PHP_EOL;
$stmt = $mysqli->prepare($sql);
if ($stmt && $stmt->execute()) {
echo '- success' . PHP_EOL;
} else {
echo '- failed: ' . $mysqli->error . PHP_EOL;
exit(1);
}
}
}
}
?>

View File

@ -0,0 +1,30 @@
<?php
function run_0014() {
// Ugly but haven't found a better way
global $setting, $config, $user, $mysqli;
// Version information
$db_version_old = '0.0.13'; // What version do we expect
$db_version_new = '0.0.14'; // What is the new version we wish to upgrade to
$db_version_now = $setting->getValue('DB_VERSION'); // Our actual version installed
// Upgrade specific variables
$aSql[] = "ALTER TABLE `statistics_users` CHANGE `hashrate` `hashrate` BIGINT UNSIGNED NOT NULL";
$aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.14' WHERE name = 'DB_VERSION'";
if ($db_version_now == $db_version_old && version_compare($db_version_now, DB_VERSION, '<')) {
// Run the upgrade
echo '- Starting database migration to version ' . $db_version_new . PHP_EOL;
foreach ($aSql as $sql) {
echo '- Preparing: ' . $sql . PHP_EOL;
$stmt = $mysqli->prepare($sql);
if ($stmt && $stmt->execute()) {
echo '- success' . PHP_EOL;
} else {
echo '- failed: ' . $mysqli->error . PHP_EOL;
exit(1);
}
}
}
}
?>