From 07d49f83d3372ec60ab0176b644b76f1dacb4f3b Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 3 Jun 2013 15:03:04 +0200
Subject: [PATCH 001/168] Changing hash- and share rate calculation SQL
* Do not include shares_archive table
* Main reason: This table is optional
* Secondary reason: Speeds up the query from 1.3s to 0.005s
* Drawback: Once a block is found it takes 10 minutes for the stats to
be accuracte again
This could potentially be reverted but since shares_archive is optional
and the speed increase is rather significant I'd like to keep it this
way.
---
public/include/classes/statistics.class.php | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index 8b12391e..b8fa232c 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -90,12 +90,8 @@ class Statistics {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
- SELECT SUM(hashrate) AS hashrate FROM
- (
- SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
- UNION
- SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
- ) AS sum");
+ SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
+ ");
// Catchall
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() ) return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->hashrate);
$this->debug->append("Failed to get hashrate: " . $this->mysqli->error);
@@ -111,12 +107,8 @@ class Statistics {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
- SELECT ROUND(SUM(sharerate) / 600, 2) AS sharerate FROM
- (
- SELECT COUNT(id) AS sharerate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
- UNION ALL
- SELECT COUNT(id) AS sharerate FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
- ) AS sum");
+ SELECT ROUND(COUNT(id) / 600, 2) AS sharerate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
+ ");
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() ) return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->sharerate);
// Catchall
$this->debug->append("Failed to fetch share rate: " . $this->mysqli->error);
From da1d7daaa2a8dcd4f25b539c1ed99c74c350f2e7 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 3 Jun 2013 20:54:58 +0200
Subject: [PATCH 002/168] Removed warning from worker list
* Workers can safely be removed even during a round
---
public/templates/mmcFE/account/workers/default.tpl | 5 -----
1 file changed, 5 deletions(-)
diff --git a/public/templates/mmcFE/account/workers/default.tpl b/public/templates/mmcFE/account/workers/default.tpl
index c09cdde3..90637260 100644
--- a/public/templates/mmcFE/account/workers/default.tpl
+++ b/public/templates/mmcFE/account/workers/default.tpl
@@ -1,9 +1,4 @@
{include file="global/block_header.tpl" BLOCK_HEADER="My Workers"}
-
- CAUTION! Deletion of a worker could cause all associated shares for that worker to be lost.
- Do not delete Workers unless you are certain all of their shares have been counted or that you have never used that worker account.
-
-
+
@@ -39,6 +40,7 @@
+ ID
Username
E-Mail
Hashrate
@@ -53,6 +55,7 @@
{section name=user loop=$USERS|default}
+ {$USERS[user].id}
{$USERS[user].username}
{$USERS[user].email}
{$USERS[user].hashrate}
@@ -69,6 +72,7 @@
+ ID
Username
E-Mail
Hashrate
From 38a66b917fe29bcb45effa4606f72708651b9c66 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 12:01:16 +0200
Subject: [PATCH 007/168] adding number format to admin user query table
---
public/templates/mmcFE/admin/user/default.tpl | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 905ee09b..147c3fe4 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -58,12 +58,12 @@
{$USERS[user].id}
{$USERS[user].username}
{$USERS[user].email}
- {$USERS[user].hashrate}
- {$USERS[user].shares.valid}
- {$USERS[user].shares.invalid}
- {$USERS[user].balance}
- {$USERS[user].payout.est_donation}
- {$USERS[user].payout.est_payout}
+ {$USERS[user].hashrate|number_format}
+ {$USERS[user].shares.valid|number_format}
+ {$USERS[user].shares.invalid|number_format}
+ {$USERS[user].balance|number_format:"8"}
+ {$USERS[user].payout.est_donation|number_format:"8"}
+ {$USERS[user].payout.est_payout|number_format:"8"}
From 43772f439bb28cea910d9ae533c221255b123d7c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 12:10:43 +0200
Subject: [PATCH 008/168] fixing sort arrows showing behind text
---
public/templates/mmcFE/admin/user/default.tpl | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 147c3fe4..4e3e0770 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -43,12 +43,12 @@
ID
Username
E-Mail
- Hashrate
- Valid
- Invalid
- Balance
- Est. Donation
- Est. Payout
+ Hashrate
+ Valid
+ Invalid
+ Balance
+ Est. Donation
+ Est. Payout
Admin
From 4fa3089655d6d2192b72ac4d86527baa7498fdfb Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 12:13:38 +0200
Subject: [PATCH 009/168] fixing JS crash when table has no content
---
public/templates/mmcFE/admin/user/default.tpl | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 4e3e0770..07b6e5f1 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -68,6 +68,10 @@
+{sectionelse}
+
+
+
{/section}
From d85ded7c5c87384e3cc4ce2c9bf4925c95f0cde1 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 13:14:25 +0200
Subject: [PATCH 010/168] Moving from user to statistics class
* This fetches all users and joins with shares table
Should speed up things a fair bit.
---
public/include/classes/statistics.class.php | 30 ++++++++++++++++++-
public/include/pages/admin/user.inc.php | 6 ++--
public/templates/mmcFE/admin/user/default.tpl | 28 +++++------------
3 files changed, 38 insertions(+), 26 deletions(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index b8fa232c..c6687ee5 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -54,7 +54,7 @@ class Statistics {
$stmt = $this->mysqli->prepare("
SELECT b.*, a.username as finder
FROM " . $this->block->getTableName() . " AS b
- LEFT JOIN accounts AS a
+ LEFT JOIN " . $this->user->getTableName() . " AS a
ON b.account_id = a.id
ORDER BY height DESC LIMIT ?");
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
@@ -175,6 +175,34 @@ class Statistics {
return false;
}
+ /**
+ * Admin panel specific query
+ * @return data array invlid and valid shares for all accounts
+ **/
+ public function getAllUserStats($filter='%') {
+ $this->debug->append("STA " . __METHOD__, 4);
+ if ($data = $this->memcache->get(__FUNCTION__ . $filter)) return $data;
+ $stmt = $this->mysqli->prepare("
+ SELECT
+ a.id AS id,
+ a.username AS username,
+ a.donate_percent AS donate_percent,
+ a.email AS email,
+ COUNT(s.id) AS shares,
+ ROUND(COUNT(s.id) * POW(2," . $this->config['difficulty'] . ") / 600 / 1000,2) AS hashrate
+ FROM " . $this->user->getTableName() . " AS a
+ LEFT JOIN " . $this->share->getTableName() . " AS s
+ ON a.username = SUBSTRING_INDEX( s.username, '.', 1 )
+ WHERE
+ a.username LIKE ?
+ GROUP BY username
+ ORDER BY username
+ ");
+ if ($this->checkStmt($stmt) && $stmt->bind_param('s', $filter) && $stmt->execute() && $result = $stmt->get_result()) {
+ return $this->memcache->setCache(__FUNCTION__ . $filter, $result->fetch_all(MYSQLI_ASSOC));
+ }
+ }
+
/**
* Same as getUserShares for Hashrate
* @param account_id integer User ID
diff --git a/public/include/pages/admin/user.inc.php b/public/include/pages/admin/user.inc.php
index 17766283..cc961f44 100644
--- a/public/include/pages/admin/user.inc.php
+++ b/public/include/pages/admin/user.inc.php
@@ -14,16 +14,14 @@ $aRoundShares = $statistics->getRoundShares();
if ($_POST['query']) {
// Fetch requested users
- $aUsers = $user->getUsers($_POST['query']);
+ $aUsers = $statistics->getAllUserStats($_POST['query']);
// Add additional stats to each user
// This is not optimized yet, best is a proper SQL
// Query against the stats table? Currently cached though.
foreach ($aUsers as $iKey => $aUser) {
$aUser['balance'] = $transaction->getBalance($aUser['id']);
- $aUser['hashrate'] = $statistics->getUserHashrate($aUser['id']);
- $aUser['shares'] = $statistics->getUserShares($aUser['id']);
- $aUser['payout']['est_block'] = round(( (int)$aUser['shares']['valid'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
+ $aUser['payout']['est_block'] = round(( (int)$aUser['shares'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
$aUser['payout']['est_fee'] = round(($config['fees'] / 100) * $aUser['payout']['est_block'], 3);
$aUser['payout']['est_donation'] = round((( $aUser['donate_percent'] / 100) * ($aUser['payout']['est_block'] - $aUser['payout']['est_fee'])), 3);
$aUser['payout']['est_payout'] = round($aUser['payout']['est_block'] - $aUser['payout']['est_donation'] - $aUser['payout']['est_fee'], 3);
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 07b6e5f1..6cd3e4fb 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -26,29 +26,16 @@
-
-
-
-
-
-
-
-
-
-
-
-
ID
Username
E-Mail
Hashrate
- Valid
- Invalid
- Balance
+ Shares
Est. Donation
Est. Payout
+ Balance
Admin
@@ -59,18 +46,17 @@
{$USERS[user].username}
{$USERS[user].email}
{$USERS[user].hashrate|number_format}
- {$USERS[user].shares.valid|number_format}
- {$USERS[user].shares.invalid|number_format}
- {$USERS[user].balance|number_format:"8"}
+ {$USERS[user].shares|number_format}
{$USERS[user].payout.est_donation|number_format:"8"}
{$USERS[user].payout.est_payout|number_format:"8"}
+ {$USERS[user].balance|number_format:"8"}
{sectionelse}
-
+
{/section}
@@ -80,10 +66,10 @@
Username
E-Mail
Hashrate
- Shares
- Balance
+ Shares
Est. Donation
Est. Payout
+ Balance
Admin
From b19473ff427ed7c9e6bc8850066dd43a04b043c6 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 13:23:00 +0200
Subject: [PATCH 011/168] sorting does not work with number_format
---
public/templates/mmcFE/admin/user/default.tpl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 6cd3e4fb..5386a84f 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -45,8 +45,8 @@
{$USERS[user].id}
{$USERS[user].username}
{$USERS[user].email}
- {$USERS[user].hashrate|number_format}
- {$USERS[user].shares|number_format}
+ {$USERS[user].hashrate / 1024}
+ {$USERS[user].shares}
{$USERS[user].payout.est_donation|number_format:"8"}
{$USERS[user].payout.est_payout|number_format:"8"}
{$USERS[user].balance|number_format:"8"}
From 020ea2269b0783450b4fc0bcaa4db4fcf4f0bbf1 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 13:46:56 +0200
Subject: [PATCH 012/168] Re-adding admin flags to user list for admin panel
Fixes #99
---
public/include/classes/statistics.class.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index c6687ee5..f9fd18c9 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -185,6 +185,7 @@ class Statistics {
$stmt = $this->mysqli->prepare("
SELECT
a.id AS id,
+ a.admin as admin,
a.username AS username,
a.donate_percent AS donate_percent,
a.email AS email,
From 91d225e340d4215fe9aca4c5e3809fb3e3e6e2a1 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 14:03:46 +0200
Subject: [PATCH 013/168] Adding wallet information in Admin panel
Fixes #63 and adds proper wallet information:
* Wallet balance
* Locked balance for users
* Liquid assets available to pool owner
---
public/include/pages/admin/wallet.inc.php | 25 +++++++++++++++++++
.../templates/mmcFE/admin/wallet/default.tpl | 16 ++++++++++++
public/templates/mmcFE/global/navigation.tpl | 1 +
3 files changed, 42 insertions(+)
create mode 100644 public/include/pages/admin/wallet.inc.php
create mode 100644 public/templates/mmcFE/admin/wallet/default.tpl
diff --git a/public/include/pages/admin/wallet.inc.php b/public/include/pages/admin/wallet.inc.php
new file mode 100644
index 00000000..cb094fe9
--- /dev/null
+++ b/public/include/pages/admin/wallet.inc.php
@@ -0,0 +1,25 @@
+isAdmin($_SESSION['USERDATA']['id'])) {
+ header("HTTP/1.1 404 Page not found");
+ die();
+}
+
+if ($bitcoin->can_connect() === true){
+ $dBalance = $bitcoin->query('getbalance');
+} else {
+ $dBalance = 0;
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
+}
+
+$smarty->assign("BALANCE", $dBalance);
+$smarty->assign("LOCKED", $transaction->getLockedBalance());
+
+// Tempalte specifics
+$smarty->assign("CONTENT", "default.tpl");
+?>
diff --git a/public/templates/mmcFE/admin/wallet/default.tpl b/public/templates/mmcFE/admin/wallet/default.tpl
new file mode 100644
index 00000000..42b8c8b3
--- /dev/null
+++ b/public/templates/mmcFE/admin/wallet/default.tpl
@@ -0,0 +1,16 @@
+{include file="global/block_header.tpl" BLOCK_HEADER="Wallet Information"}
+
+
+ Wallet Balance
+ {$BALANCE|number_format:"8"}
+
+
+ Locked for users
+ {$LOCKED|number_format:"8"}
+
+
+ Liquid Assets
+ {($BALANCE - $LOCKED)|number_format:"8"}
+
+
+{include file="global/block_footer.tpl"}
diff --git a/public/templates/mmcFE/global/navigation.tpl b/public/templates/mmcFE/global/navigation.tpl
index 13172478..6a0cdb37 100644
--- a/public/templates/mmcFE/global/navigation.tpl
+++ b/public/templates/mmcFE/global/navigation.tpl
@@ -14,6 +14,7 @@
Admin Panel
{/if}
From af3252abb20aa7ec4cfacb03ff046e770fb25886 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 14:28:34 +0200
Subject: [PATCH 014/168] Find ALL transactions, even unconfirmed
* This ensures that credits are not unlocked and available to the pool
---
public/include/classes/transaction.class.php | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index 15f29c77..020140d3 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -130,6 +130,7 @@ class Transaction {
/**
* Get total balance for all users locked in wallet
+ * This includes any outstanding unconfirmed transactions!
* @param none
* @return data double Amount locked for users
**/
@@ -141,9 +142,7 @@ class Transaction {
(
SELECT sum(t.amount) AS credit
FROM $this->table AS t
- LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type = 'Credit'
- AND b.confirmations >= ?
) AS t1,
(
SELECT sum(t.amount) AS debit
@@ -152,12 +151,10 @@ class Transaction {
) AS t2,
(
SELECT sum(t.amount) AS other
- FROM transactions AS t
- LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
+ FROM " . $this->table . " AS t
WHERE t.type IN ('Donation','Fee')
- AND b.confirmations >= ?
) AS t3");
- if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $this->config['confirmations'], $this->config['confirmations']) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
+ if ($this->checkStmt($stmt) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
return $dBalance;
// Catchall
$this->setErrorMessage('Unable to find locked credits for all users');
From 4277fb26cc59ce0cd5d4cfb7c2b7a26f5efc6631 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 15:10:07 +0200
Subject: [PATCH 015/168] Removed PHP Notice warning when running cron
This fixes #102, we don't need to see this warning since it doesn't
affect the job at all.
---
cronjobs/proportional_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/proportional_payout.php b/cronjobs/proportional_payout.php
index 30d0b018..d22d1f19 100755
--- a/cronjobs/proportional_payout.php
+++ b/cronjobs/proportional_payout.php
@@ -32,7 +32,7 @@ if (empty($aAllBlocks)) {
$count = 0;
foreach ($aAllBlocks as $iIndex => $aBlock) {
if (!$aBlock['accounted']) {
- $iPreviousShareId = $aAllBlocks[$iIndex - 1]['share_id'] ? $aAllBlocks[$iIndex - 1]['share_id'] : 0;
+ $iPreviousShareId = @$aAllBlocks[$iIndex - 1]['share_id'] ? $aAllBlocks[$iIndex - 1]['share_id'] : 0;
$iCurrentUpstreamId = $aBlock['share_id'];
$aAccountShares = $share->getSharesForAccounts($iPreviousShareId, $aBlock['share_id']);
$iRoundShares = $share->getRoundShares($iPreviousShareId, $aBlock['share_id']);
From 930bb508001811f856b8bf10b1313d3a8bbd7699 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 15:49:52 +0200
Subject: [PATCH 016/168] Update README.md
---
README.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/README.md b/README.md
index 66e3dcc2..b8b1f0a8 100644
--- a/README.md
+++ b/README.md
@@ -71,6 +71,11 @@ The following feature have been implemented so far:
* Manual payout with 0.1 LTC fee
* Auto payout with 0.1 LTC fee
* Transaction list (confirmed and unconfirmed)
+* Admin Panel
+ * User Listing including statistics
+ * Wallet information
+ * (Planned) News Posts
+ * (Planned) Pool Donations
Installation
============
From c1682e22030dd82a769c3fbe8704337cbff3baa4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 15:58:51 +0200
Subject: [PATCH 017/168] Ignore rejected shares in top list calculations
Fixes #104
---
public/include/classes/statistics.class.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index f9fd18c9..c261a884 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -263,6 +263,7 @@ class Statistics {
COUNT(id) AS shares,
SUBSTRING_INDEX( username, '.', 1 ) AS account
FROM " . $this->share->getTableName() . "
+ WHERE our_result = 'Y'
GROUP BY account
ORDER BY shares DESC
LIMIT ?");
@@ -279,6 +280,7 @@ class Statistics {
SUBSTRING_INDEX( username, '.', 1 ) AS account
FROM " . $this->share->getTableName() . "
WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
+ AND our_result = 'Y'
GROUP BY account
ORDER BY hashrate DESC LIMIT ?");
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
From e37fb70a46899d2849c0e11bee62bdd712094585 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 4 Jun 2013 20:51:24 +0200
Subject: [PATCH 018/168] Do not deduct fees from balance when transmitting
Fixes #106, we want to transfer the entire balance and let the RPC
server deduct any fees that might apply.
---
cronjobs/auto_payout.php | 6 +++---
public/include/pages/account/edit.inc.php | 5 +++--
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/cronjobs/auto_payout.php b/cronjobs/auto_payout.php
index 3454ad9c..68b60aa4 100755
--- a/cronjobs/auto_payout.php
+++ b/cronjobs/auto_payout.php
@@ -38,7 +38,7 @@ if (! empty($users)) {
$dBalance = $transaction->getBalance($aUserData['id']);
verbose($aUserData['id'] . "\t" . $aUserData['username'] . "\t" . $dBalance . "\t" . $aUserData['ap_threshold'] . "\t\t" . $aUserData['coin_address'] . "\t");
- // Only run if balance meets threshold and can pay the transaction fee
+ // Only run if balance meets threshold and can pay the potential transaction fee
if ($dBalance > $aUserData['ap_threshold'] && $dBalance > 0.1) {
// Validate address against RPC
try {
@@ -48,9 +48,9 @@ if (! empty($users)) {
continue;
}
- // Send balance - 0.1 Fee to address
+ // Send balance, fees are reduced later
try {
- $bitcoin->sendtoaddress($aUserData['coin_address'], $dBalance - 0.1);
+ $bitcoin->sendtoaddress($aUserData['coin_address'], $dBalance);
} catch (BitcoinClientException $e) {
verbose("SEND FAILED\n");
continue;
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index bb29cace..6308e271 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -16,6 +16,7 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
$continue = true;
$dBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
$sCoinAddress = $user->getCoinAddress($_SESSION['USERDATA']['id']);
+ // Ensure we can cover the potential transaction fee of 0.1 LTC with the balance
if ($dBalance > 0.1) {
if ($bitcoin->can_connect() === true) {
try {
@@ -25,9 +26,9 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
$continue = false;
}
if ($continue == true) {
- // Remove the transfer fee and send to address
+ // Send balance to address, mind 0.1 fee for transaction!
try {
- $bitcoin->sendtoaddress($sCoinAddress, $dBalance - 0.1);
+ $bitcoin->sendtoaddress($sCoinAddress, $dBalance);
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send LTC, please contact site support immidiately', 'TYPE' => 'errormsg');
$continue = false;
From 6c4fb84ee909ccdd27e04cf9f60019a2b718bca3 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 5 Jun 2013 09:11:25 +0200
Subject: [PATCH 019/168] Adding min/max threshold configuration
* Check for min/max values set for auto payouts
* Display error messages to the user
* Sanitize values just in case we fall through the validation
* Updated template and class
* New configuration option added! Update your local configs!
Fixes #108
---
public/include/classes/user.class.php | 21 +++++++++++++++++++--
public/include/config/global.inc.dist.php | 4 ++++
public/include/pages/account/edit.inc.php | 2 +-
3 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 2b5f093e..8db17a1e 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -241,10 +241,27 @@ class User {
public function updateAccount($userID, $address, $threshold, $donate) {
$this->debug->append("STA " . __METHOD__, 4);
$bUser = false;
- $threshold = min(250, max(0, floatval($threshold)));
- if ($threshold < 1) $threshold = 0.0;
+
+ // number validation checks
+ if ($threshold < $this->config['ap_threshold']['min'] && $threshold != 0) {
+ $this->setErrorMessage('Threshold below configured minimum of ' . $this->config['ap_threshold']['min']);
+ return false;
+ } else if ($threshold > $this->config['ap_threshold']['max']) {
+ $this->setErrorMessage('Threshold above configured maximum of ' . $this->config['ap_threshold']['max']);
+ return false;
+ }
+ if ($donate < 0) {
+ $this->setErrorMessage('Donation below allowed 0% limit');
+ return false;
+ } else if ($donate > 100) {
+ $this->setErrorMessage('Donation above allowed 100% limit');
+ return false;
+ }
+ // Number sanitizer, just in case we fall through above
+ $threshold = min($this->config['ap_threshold']['max'], max(0, floatval($threshold)));
$donate = min(100, max(0, floatval($donate)));
+ // We passed all validation checks so update the account
$stmt = $this->mysqli->prepare("UPDATE $this->table SET coin_address = ?, ap_threshold = ?, donate_percent = ? WHERE id = ?");
$stmt->bind_param('sddi', $address, $threshold, $donate, $userID);
$stmt->execute();
diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php
index 2bb6069f..306d5261 100644
--- a/public/include/config/global.inc.dist.php
+++ b/public/include/config/global.inc.dist.php
@@ -25,6 +25,10 @@ $config = array(
'url' => 'https://btc-e.com/api/2',
'target' => '/ltc_usd/ticker'
),
+ 'ap_threshold' => array(
+ 'min' => 1,
+ 'max' => 250
+ ),
'website' => array(
'name' => 'The Pool',
'slogan' => 'Resistance is futile',
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index 6308e271..84937115 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -49,7 +49,7 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
} else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account', 'TYPE' => 'errormsg');
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'errormsg');
}
break;
From 11338cedf3e3a8e09d8a24b6ee2a93debfc0011c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 5 Jun 2013 09:17:10 +0200
Subject: [PATCH 020/168] Add new threshold display to template
Forgot to add the template files that adds configurable thresholds
---
public/include/smarty_globals.inc.php | 8 +++++++-
public/templates/mmcFE/account/edit/default.tpl | 2 +-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index f34b3b4a..fa5c7923 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -25,7 +25,13 @@ $aGlobal = array(
'reward' => $config['reward'],
'price' => $setting->getValue('price'),
'blockexplorer' => $config['blockexplorer'],
- 'chaininfo' => $config['chaininfo']
+ 'chaininfo' => $config['chaininfo'],
+ 'config' => array(
+ 'ap_threshold' => array(
+ 'min' => $config['ap_threshold']['min'],
+ 'max' => $config['ap_threshold']['max']
+ )
+ )
);
// We don't want these session infos cached
diff --git a/public/templates/mmcFE/account/edit/default.tpl b/public/templates/mmcFE/account/edit/default.tpl
index 9d885b16..2fc9b4a9 100644
--- a/public/templates/mmcFE/account/edit/default.tpl
+++ b/public/templates/mmcFE/account/edit/default.tpl
@@ -9,7 +9,7 @@
API Key: {$GLOBAL.userdata.api_key}
Payment Address:
Donation %: [donation amount in percent (example: 0.5)]
- Automatic Payout Threshold: [1-250 LTC. Set to '0' for no auto payout]
+ Automatic Payout Threshold: [{$GLOBAL.config.ap_threshold.min}-{$GLOBAL.config.ap_threshold.max} LTC. Set to '0' for no auto payout]
4 digit PIN: [The 4 digit PIN you chose when registering]
From aff116849cb9a750f315f36b819de64a6907fdcc Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 5 Jun 2013 11:49:08 +0200
Subject: [PATCH 021/168] Adding support for public API polling
* Does not require a token
* Returns basic status as taken from default mmcfe
Addresses #111
---
public/include/pages/api/public.inc.php | 26 +++++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 public/include/pages/api/public.inc.php
diff --git a/public/include/pages/api/public.inc.php b/public/include/pages/api/public.inc.php
new file mode 100644
index 00000000..162e9134
--- /dev/null
+++ b/public/include/pages/api/public.inc.php
@@ -0,0 +1,26 @@
+getLast();
+$aShares = $statistics->getRoundShares();
+
+echo json_encode(
+ array(
+ 'pool_name' => $config['website']['name'],
+ 'hashrate' => $statistics->getCurrentHashrate(),
+ 'workers' => $worker->getCountAllActiveWorkers(),
+ 'shares_this_round' => $aShares['valid'],
+ 'last_block' => $aLastBlock['height'],
+ 'network_hashrate' => '0'
+ )
+);
+
+// Supress master template
+$supress_master = 1;
+?>
From 8ee987a98d92430ede5cb47e79abb2b9c000a785 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 5 Jun 2013 15:31:53 +0200
Subject: [PATCH 022/168] Adding reference to API on public stats page
Addresses #113
---
public/templates/mmcFE/statistics/default.tpl | 1 +
1 file changed, 1 insertion(+)
diff --git a/public/templates/mmcFE/statistics/default.tpl b/public/templates/mmcFE/statistics/default.tpl
index d1dfd202..a8e9a4c2 100644
--- a/public/templates/mmcFE/statistics/default.tpl
+++ b/public/templates/mmcFE/statistics/default.tpl
@@ -19,4 +19,5 @@
+These stats are also available in JSON format HERE
{include file="global/block_footer.tpl"}
From 7dc0736b777917bb535799ed224fff1a8853d398 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 5 Jun 2013 17:22:47 +0200
Subject: [PATCH 023/168] First version for new user graphs
* Properly calculate hashrate
* Remove number formatting, it breaks the graph
* Not properly in order based on time but displays correct values
Addresses #90
---
public/include/classes/statistics.class.php | 24 +++++++++----------
public/include/pages/statistics/user.inc.php | 10 --------
.../mmcFE/statistics/user/default.tpl | 2 +-
3 files changed, 13 insertions(+), 23 deletions(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index c261a884..87969707 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -302,22 +302,22 @@ class Statistics {
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
- ROUND(COUNT(s.id) * POW(2, 12)/600/1000) AS hashrate,
+ ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ")/3600/1000) AS hashrate,
HOUR(s.time) AS hour
- FROM " . $this->share->getTableName() . " AS s, accounts AS a
+ FROM " . $this->share->getTableName() . " AS s, accounts AS a
WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
AND a.id = ?
- GROUP BY HOUR(time)
- UNION ALL
- SELECT
- ROUND(COUNT(s.id) * POW(2, 12)/600/1000) AS hashrate,
- HOUR(s.time) AS hour
- FROM " . $this->share->getArchiveTableName() . " AS s, accounts AS a
- WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
- AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
- AND a.id = ?
- GROUP BY HOUR(time)");
+ GROUP BY HOUR(time)
+ UNION ALL
+ SELECT
+ ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ")/3600/1000) AS hashrate,
+ HOUR(s.time) AS hour
+ FROM " . $this->share->getArchiveTableName() . " AS s, accounts AS a
+ WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
+ AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
+ AND a.id = ?
+ GROUP BY HOUR(time)");
if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $account_id, $account_id) && $stmt->execute() && $result = $stmt->get_result())
return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_all(MYSQLI_ASSOC), 3600);
// Catchall
diff --git a/public/include/pages/statistics/user.inc.php b/public/include/pages/statistics/user.inc.php
index 41440b99..2a713925 100644
--- a/public/include/pages/statistics/user.inc.php
+++ b/public/include/pages/statistics/user.inc.php
@@ -4,16 +4,6 @@
if (!defined('SECURITY'))
die('Hacking attempt');
-// Fetch data from litecoind
-if ($bitcoin->can_connect() === true){
- $dDifficulty = $bitcoin->getdifficulty();
- $iBlock = $bitcoin->getblockcount();
-} else {
- $iDifficulty = 1;
- $iBlock = 0;
- $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
-}
-
$aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']);
// Propagate content our template
diff --git a/public/templates/mmcFE/statistics/user/default.tpl b/public/templates/mmcFE/statistics/user/default.tpl
index ffc5e8c8..dee8180e 100644
--- a/public/templates/mmcFE/statistics/user/default.tpl
+++ b/public/templates/mmcFE/statistics/user/default.tpl
@@ -14,7 +14,7 @@
{$GLOBAL.USERDATA.username}
{section hashrate $YOURHASHRATES}
- {$YOURHASHRATES[hashrate].hashrate|number_format}
+ {$YOURHASHRATES[hashrate].hashrate}
{/section}
From 52d079eaed514b30240bd768d1b734a6b8593bc8 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 10:45:37 +0200
Subject: [PATCH 024/168] do not include archive table for hashrates, better
formatting
---
public/include/classes/statistics.class.php | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index 87969707..be101068 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -302,22 +302,15 @@ class Statistics {
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
- ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ")/3600/1000) AS hashrate,
+ ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ") / 3600 / 1000) AS hashrate,
HOUR(s.time) AS hour
FROM " . $this->share->getTableName() . " AS s, accounts AS a
- WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
+ WHERE time < NOW() - INTERVAL 1 HOUR
+ AND time > NOW() - INTERVAL 25 HOUR
AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
AND a.id = ?
GROUP BY HOUR(time)
- UNION ALL
- SELECT
- ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ")/3600/1000) AS hashrate,
- HOUR(s.time) AS hour
- FROM " . $this->share->getArchiveTableName() . " AS s, accounts AS a
- WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
- AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
- AND a.id = ?
- GROUP BY HOUR(time)");
+ ");
if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $account_id, $account_id) && $stmt->execute() && $result = $stmt->get_result())
return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_all(MYSQLI_ASSOC), 3600);
// Catchall
From 232e79f7ad6aeeac574d1ee83e0255f15b4e59d6 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 11:01:04 +0200
Subject: [PATCH 025/168] do not pass two arguments to SQL
---
public/include/classes/statistics.class.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index be101068..edbc24a0 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -311,7 +311,7 @@ class Statistics {
AND a.id = ?
GROUP BY HOUR(time)
");
- if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $account_id, $account_id) && $stmt->execute() && $result = $stmt->get_result())
+ if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result())
return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_all(MYSQLI_ASSOC), 3600);
// Catchall
$this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
From 1bf2e7cf181ca5b9e38c3a6a1a6ba2c24e79b8ef Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 11:47:20 +0200
Subject: [PATCH 026/168] Pre-sort SQL data in array for easy time access
This allows us to access the array key as the time. This way the
template can properly render the time axis according to current time.
---
public/include/classes/statistics.class.php | 8 +++++--
public/include/pages/statistics/user.inc.php | 1 -
.../mmcFE/statistics/user/default.tpl | 22 ++++++++++++++-----
3 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index edbc24a0..a85cb145 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -311,8 +311,12 @@ class Statistics {
AND a.id = ?
GROUP BY HOUR(time)
");
- if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result())
- return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_all(MYSQLI_ASSOC), 3600);
+ if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result()) {
+ while ($row = $result->fetch_assoc()) {
+ $aData[$row['hour']] = $row['hashrate'];
+ }
+ return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData, 3600);
+ }
// Catchall
$this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
return false;
diff --git a/public/include/pages/statistics/user.inc.php b/public/include/pages/statistics/user.inc.php
index 2a713925..2b0b0ed9 100644
--- a/public/include/pages/statistics/user.inc.php
+++ b/public/include/pages/statistics/user.inc.php
@@ -8,7 +8,6 @@ $aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA'
// Propagate content our template
$smarty->assign("YOURHASHRATES", $aHourlyHashRates);
-$smarty->assign("DIFFICULTY", $dDifficulty);
if ($_SESSION['AUTHENTICATED']) {
$smarty->assign("CONTENT", "default.tpl");
diff --git a/public/templates/mmcFE/statistics/user/default.tpl b/public/templates/mmcFE/statistics/user/default.tpl
index dee8180e..201c783c 100644
--- a/public/templates/mmcFE/statistics/user/default.tpl
+++ b/public/templates/mmcFE/statistics/user/default.tpl
@@ -1,23 +1,33 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Your Average Hourly Hash Rate" BUTTONS=array(mine,pool,both)}
+{if is_array($YOURHASHRATES)}
Your Hashrate
-{section hashrate $YOURHASHRATES}
- {$YOURHASHRATES[hashrate].hour}
-{/section}
+{for $i=date('G', time() + 60 * 60) to 23}
+ {$i}
+{/for}
+{for $i=0 to date('G')}
+ {$i}
+{/for}
{$GLOBAL.USERDATA.username}
-{section hashrate $YOURHASHRATES}
- {$YOURHASHRATES[hashrate].hashrate}
-{/section}
+{for $i=date('G', time() + 60 * 60) to 23}
+ {$YOURHASHRATES.$i|default:"0"}
+{/for}
+{for $i=0 to date('G')}
+ {$YOURHASHRATES.$i|default:"0"}
+{/for}
+{else}
+
No shares available to start calculations
+{/if}
{include file="global/block_footer.tpl"}
From 8fccc8fe3a960a26ce07e541ead21c678ed9e7ea Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 11:57:46 +0200
Subject: [PATCH 027/168] proper time range
---
public/templates/mmcFE/statistics/user/default.tpl | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/public/templates/mmcFE/statistics/user/default.tpl b/public/templates/mmcFE/statistics/user/default.tpl
index 201c783c..aec27d29 100644
--- a/public/templates/mmcFE/statistics/user/default.tpl
+++ b/public/templates/mmcFE/statistics/user/default.tpl
@@ -6,21 +6,21 @@
-{for $i=date('G', time() + 60 * 60) to 23}
- {$i}
+{for $i=date('G') to 23}
+ {$i}:00
{/for}
-{for $i=0 to date('G')}
- {$i}
+{for $i=0 to date('G', time () - 60 * 60)}
+ {$i}:00
{/for}
{$GLOBAL.USERDATA.username}
-{for $i=date('G', time() + 60 * 60) to 23}
+{for $i=date('G') to 23}
{$YOURHASHRATES.$i|default:"0"}
{/for}
-{for $i=0 to date('G')}
+{for $i=0 to date('G', time() - 60 * 60)}
{$YOURHASHRATES.$i|default:"0"}
{/for}
From aebb97a1d86786568717baaeef77eaa0fb65e2eb Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 12:01:06 +0200
Subject: [PATCH 028/168] use default cashing times
---
public/include/classes/statistics.class.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index a85cb145..4ed74bb4 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -315,7 +315,7 @@ class Statistics {
while ($row = $result->fetch_assoc()) {
$aData[$row['hour']] = $row['hashrate'];
}
- return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData, 3600);
+ return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData);
}
// Catchall
$this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
From 7e76bb4a63110ffff83d3d2dc4d9ed86c2a4549a Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 12:02:58 +0200
Subject: [PATCH 029/168] properly display username in graph
---
public/templates/mmcFE/statistics/user/default.tpl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/templates/mmcFE/statistics/user/default.tpl b/public/templates/mmcFE/statistics/user/default.tpl
index aec27d29..dc285321 100644
--- a/public/templates/mmcFE/statistics/user/default.tpl
+++ b/public/templates/mmcFE/statistics/user/default.tpl
@@ -16,7 +16,7 @@
- {$GLOBAL.USERDATA.username}
+ {$smarty.session.USERDATA.username}
{for $i=date('G') to 23}
{$YOURHASHRATES.$i|default:"0"}
{/for}
From e3702a5804d6c6b5a5bb9bff7464b72d9e68d9b3 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 13:37:05 +0200
Subject: [PATCH 030/168] better looking worker table
---
public/templates/mmcFE/account/workers/default.tpl | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/public/templates/mmcFE/account/workers/default.tpl b/public/templates/mmcFE/account/workers/default.tpl
index 90637260..f1b6e875 100644
--- a/public/templates/mmcFE/account/workers/default.tpl
+++ b/public/templates/mmcFE/account/workers/default.tpl
@@ -9,18 +9,18 @@
Worker Name
Password
- Active
- Khash/s
+ Active
+ Khash/s
{section worker $WORKERS}
{assign var="username" value="."|escape|explode:$WORKERS[worker].username:2}
- {$username.0|escape}.
+ {$username.0|escape}.
- {if $WORKERS[worker].active == 1}Y{else}N{/if}
- {$WORKERS[worker].hashrate}
+
+ {$WORKERS[worker].hashrate|number_format}
Delete
{/section}
From 2c56066763f86f6875b23a58cfd14f51b36d94e4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 15:15:27 +0200
Subject: [PATCH 031/168] changed time-range for graphs
---
public/templates/mmcFE/statistics/user/default.tpl | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/public/templates/mmcFE/statistics/user/default.tpl b/public/templates/mmcFE/statistics/user/default.tpl
index dc285321..235ec574 100644
--- a/public/templates/mmcFE/statistics/user/default.tpl
+++ b/public/templates/mmcFE/statistics/user/default.tpl
@@ -6,10 +6,10 @@
-{for $i=date('G') to 23}
+{for $i=date('G', time() - 60 * 60) to 23}
{$i}:00
{/for}
-{for $i=0 to date('G', time () - 60 * 60)}
+{for $i=0 to date('G', time () - 2 * 60 * 60)}
{$i}:00
{/for}
@@ -17,10 +17,10 @@
{$smarty.session.USERDATA.username}
-{for $i=date('G') to 23}
+{for $i=date('G', time() - 60 * 60) to 23}
{$YOURHASHRATES.$i|default:"0"}
{/for}
-{for $i=0 to date('G', time() - 60 * 60)}
+{for $i=0 to date('G', time() - 2 * 60 * 60)}
{$YOURHASHRATES.$i|default:"0"}
{/for}
From 3094c9bb9d832bb41539285c817fcea02596a638 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 16:54:21 +0200
Subject: [PATCH 032/168] re-adjusting template again
---
public/templates/mmcFE/statistics/user/default.tpl | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/public/templates/mmcFE/statistics/user/default.tpl b/public/templates/mmcFE/statistics/user/default.tpl
index 235ec574..dc285321 100644
--- a/public/templates/mmcFE/statistics/user/default.tpl
+++ b/public/templates/mmcFE/statistics/user/default.tpl
@@ -6,10 +6,10 @@
-{for $i=date('G', time() - 60 * 60) to 23}
+{for $i=date('G') to 23}
{$i}:00
{/for}
-{for $i=0 to date('G', time () - 2 * 60 * 60)}
+{for $i=0 to date('G', time () - 60 * 60)}
{$i}:00
{/for}
@@ -17,10 +17,10 @@
{$smarty.session.USERDATA.username}
-{for $i=date('G', time() - 60 * 60) to 23}
+{for $i=date('G') to 23}
{$YOURHASHRATES.$i|default:"0"}
{/for}
-{for $i=0 to date('G', time() - 2 * 60 * 60)}
+{for $i=0 to date('G', time() - 60 * 60)}
{$YOURHASHRATES.$i|default:"0"}
{/for}
From d5866207c13e9f6ef33fb9f4a7835876157c1df4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 17:18:55 +0200
Subject: [PATCH 033/168] Adding admin only API call: getuserworkers
* Require valid token and admin access
* Grab full worker information for a user
* Matches the Worker List on the Account page
* See Wiki for full documentation
---
.../include/pages/api/getuserworkers.inc.php | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 public/include/pages/api/getuserworkers.inc.php
diff --git a/public/include/pages/api/getuserworkers.inc.php b/public/include/pages/api/getuserworkers.inc.php
new file mode 100644
index 00000000..23bdcf5d
--- /dev/null
+++ b/public/include/pages/api/getuserworkers.inc.php
@@ -0,0 +1,24 @@
+checkApiKey($_REQUEST['api_key']);
+
+// We have to check if that user is admin too
+if ( ! $user->isAdmin($id) ) {
+ header("HTTP/1.1 401 Unauthorized");
+ die("Access denied");
+}
+
+// Is it a username or a user ID
+ctype_digit($_REQUEST['id']) ? $id = $_REQUEST['id'] : $id = $user->getUserId($_REQUEST['id']);
+
+// Output JSON format
+echo json_encode(array('getuserworkers' => $worker->getWorkers($id)));
+
+// Supress master template
+$supress_master = 1;
+?>
From c7e9aaac0916bf9b35ae56a0dae1b946e2057518 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 17:28:41 +0200
Subject: [PATCH 034/168] adding proper credits since only the UI code is still
the original
---
public/templates/mmcFE/global/footer.tpl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/public/templates/mmcFE/global/footer.tpl b/public/templates/mmcFE/global/footer.tpl
index bf425d19..cef5c014 100644
--- a/public/templates/mmcFE/global/footer.tpl
+++ b/public/templates/mmcFE/global/footer.tpl
@@ -1,5 +1,5 @@
- Litecoin Pool using litecoind , pushpoold
- mmcfe-ng Website based on mmcfe , overhauled by TheSerapher, available on GitHub
+ Litecoin Pool using litecoind , pushpoold , stratum-mining
+ mmcfe-ng Website based on mmcfe by AnnihilaT overhauled by TheSerapher, available on GitHub
LTC: Lge95QR2frp9y1wJufjUPCycVsg5gLJPW8
From 9286508342e612c509368b3048b6e0b6d0a32f91 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 21:04:43 +0200
Subject: [PATCH 035/168] new database structure for future features
---
sql/mmcfe_ng_structure.sql | 44 +++++++++++++++++++-------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/sql/mmcfe_ng_structure.sql b/sql/mmcfe_ng_structure.sql
index 4b6bf27d..c3c626bd 100644
--- a/sql/mmcfe_ng_structure.sql
+++ b/sql/mmcfe_ng_structure.sql
@@ -3,7 +3,7 @@
-- http://www.phpmyadmin.net
--
-- Host: localhost
--- Generation Time: May 31, 2013 at 02:31 PM
+-- Generation Time: Jun 06, 2013 at 09:01 PM
-- Server version: 5.5.31-0ubuntu0.13.04.1
-- PHP Version: 5.4.9-4ubuntu2
@@ -65,7 +65,24 @@ CREATE TABLE IF NOT EXISTS `blocks` (
PRIMARY KEY (`id`),
UNIQUE KEY `height` (`height`,`blockhash`),
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';
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `pool_worker`
+--
+
+CREATE TABLE IF NOT EXISTS `pool_worker` (
+ `id` int(255) NOT NULL AUTO_INCREMENT,
+ `account_id` int(255) NOT NULL,
+ `username` char(50) DEFAULT NULL,
+ `password` char(255) DEFAULT NULL,
+ `monitor` tinyint(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `username` (`username`),
+ KEY `account_id` (`account_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -100,7 +117,7 @@ CREATE TABLE IF NOT EXISTS `shares` (
KEY `upstream_result` (`upstream_result`),
KEY `our_result` (`our_result`),
KEY `username` (`username`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -147,7 +164,7 @@ CREATE TABLE IF NOT EXISTS `statistics_shares` (
CREATE TABLE IF NOT EXISTS `transactions` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`account_id` int(255) unsigned NOT NULL,
- `type` enum('Credit','Debit_MP','Debit_AP','Donation','Fee','Orphan_Credit','Orphan_Fee','Orphan_Donation') DEFAULT NULL,
+ `type` enum('Credit','Debit_MP','Debit_AP','Donation','Fee','Orphan_Credit','Orphan_Fee','Orphan_Donation','Credit_PPS','Fee_PPS','Donation_PPS') DEFAULT NULL,
`coin_address` varchar(255) DEFAULT NULL,
`amount` double DEFAULT '0',
`block_id` int(255) DEFAULT NULL,
@@ -156,24 +173,7 @@ CREATE TABLE IF NOT EXISTS `transactions` (
KEY `block_id` (`block_id`),
KEY `account_id` (`account_id`),
KEY `type` (`type`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `pool_worker`
---
-
-CREATE TABLE IF NOT EXISTS `pool_worker` (
- `id` int(255) NOT NULL AUTO_INCREMENT,
- `account_id` int(255) NOT NULL,
- `username` char(50) DEFAULT NULL,
- `password` char(255) DEFAULT NULL,
- `hashrate` int(11) DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `username` (`username`),
- KEY `account_id` (`account_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
From 596b0eac9300769a2c72e631417414dc0368e9e6 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 21:31:05 +0200
Subject: [PATCH 036/168] Moving shares per block into findblock cron
To better support more payout systems I have moved the share calculation
for a block into the findblock cron. This way these statistics are
always available and not depending on the actual payout method.
---
cronjobs/findblock.php | 14 +++++++++++++-
cronjobs/proportional_payout.php | 9 ---------
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php
index 025c1d3d..64d32914 100755
--- a/cronjobs/findblock.php
+++ b/cronjobs/findblock.php
@@ -66,11 +66,15 @@ if (empty($aTransactions['transactions'])) {
}
}
+verbose("\n\n");
// Now with our blocks added we can scan for their upstream shares
$aAllBlocks = $block->getAllUnaccounted('ASC');
+if (empty($aAllBlocks)) {
+ verbose("No new unaccounted blocks found\n");
+}
// Loop through our unaccounted blocks
-verbose("Block ID\tBlock Height\tShare ID\tFinder\t\t\tStatus\n");
+verbose("Block ID\tBlock Height\tShare ID\tShares\tFinder\t\t\tStatus\n");
foreach ($aAllBlocks as $iIndex => $aBlock) {
if (empty($aBlock['share_id'])) {
// Fetch this blocks upstream ID
@@ -82,16 +86,24 @@ foreach ($aAllBlocks as $iIndex => $aBlock) {
verbose($share->getError() . "\n");
continue;
}
+ // Fetch share information
+ $iPreviousShareId = @$aAllBlocks[$iIndex - 1]['share_id'] ? $aAllBlocks[$iIndex - 1]['share_id'] : 0;
+ $iRoundShares = $share->getRoundShares($iPreviousShareId, $iCurrentUpstreamId);
+
// Store new information
$strStatus = "OK";
if (!$block->setShareId($aBlock['id'], $iCurrentUpstreamId))
$strStatus = "Share ID Failed";
if (!$block->setFinder($aBlock['id'], $iAccountId))
$strStatus = "Finder Failed";
+ if (!$block->setShares($aBlock['id'], $iRoundShares))
+ $strStatus = "Shares Failed";
+
verbose(
$aBlock['id'] . "\t\t"
. $aBlock['height'] . "\t\t"
. $iCurrentUpstreamId . "\t\t"
+ . $iRoundShares . "\t"
. "[$iAccountId] " . $user->getUserName($iAccountId) . "\t\t"
. $strStatus
. "\n"
diff --git a/cronjobs/proportional_payout.php b/cronjobs/proportional_payout.php
index d22d1f19..e99387f2 100755
--- a/cronjobs/proportional_payout.php
+++ b/cronjobs/proportional_payout.php
@@ -37,20 +37,11 @@ foreach ($aAllBlocks as $iIndex => $aBlock) {
$aAccountShares = $share->getSharesForAccounts($iPreviousShareId, $aBlock['share_id']);
$iRoundShares = $share->getRoundShares($iPreviousShareId, $aBlock['share_id']);
- // Table header for block details
- verbose("ID\tHeight\tTime\t\tShares\tFinder\t\tShare ID\tPrev Share\t\tStatus\n");
- verbose($aBlock['id'] . "\t" . $aBlock['height'] . "\t" . $aBlock['time'] . "\t" . $iRoundShares . "\t" . $user->getUserName($aBlock['account_id']) . "\t" . $iCurrentUpstreamId . "\t\t" . $iPreviousShareId);
-
if (empty($aAccountShares)) {
verbose("\nNo shares found for this block\n\n");
sleep(2);
continue;
}
- $strStatus = "OK";
- // Store share information for this block
- if (!$block->setShares($aBlock['id'], $iRoundShares))
- $strStatus = "Shares Failed";
- verbose("\t\t$strStatus\n\n");
// Table header for account shares
verbose("ID\tUsername\tValid\tInvalid\tPercentage\tPayout\t\tDonation\tFee\t\tStatus\n");
From 4691e077e2a69a375d85a84c9a5ca12c018afe53 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 22:27:34 +0200
Subject: [PATCH 037/168] Ensure no old blocks shares are counter for new ones
When finding more than a single block between runs it added shares to a
new block from a previous one. Properly fetch the last highest share ID
from the database prior to scanning for shares assigned to a block.
Fixes #124
---
cronjobs/findblock.php | 6 +++++-
public/include/classes/block.class.php | 12 ++++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php
index 64d32914..2f978eed 100755
--- a/cronjobs/findblock.php
+++ b/cronjobs/findblock.php
@@ -87,7 +87,11 @@ foreach ($aAllBlocks as $iIndex => $aBlock) {
continue;
}
// Fetch share information
- $iPreviousShareId = @$aAllBlocks[$iIndex - 1]['share_id'] ? $aAllBlocks[$iIndex - 1]['share_id'] : 0;
+ if (!$iPreviousShareId = $block->getLastShareId()) {
+ $iPreviousShareId = 0;
+ verbose("\nUnable to find highest share ID found so far\n");
+ verbose("If this is your first block, this is normal\n\n");
+ }
$iRoundShares = $share->getRoundShares($iPreviousShareId, $iCurrentUpstreamId);
// Store new information
diff --git a/public/include/classes/block.class.php b/public/include/classes/block.class.php
index aad32c08..743ce67e 100644
--- a/public/include/classes/block.class.php
+++ b/public/include/classes/block.class.php
@@ -43,6 +43,18 @@ class Block {
return false;
}
+ /**
+ * Get our last, highest share ID inserted for a block
+ * @param none
+ * @return int data Share ID
+ **/
+ public function getLastShareId() {
+ $stmt = $this->mysqli->prepare("SELECT MAX(share_id) AS share_id FROM $this->table LIMIT 1");
+ if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_object()->share_id;
+ return false;
+ }
+
/**
* Fetch all unaccounted blocks
* @param order string Sort order, default ASC
From 7c1d51cc7a33560318f535229a3f2960ad6123af Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 22:40:51 +0200
Subject: [PATCH 038/168] Add API call for getuserstatus
Fixes #126, see Github Wiki for documentation
---
.../include/pages/api/getuserstatus.inc.php | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 public/include/pages/api/getuserstatus.inc.php
diff --git a/public/include/pages/api/getuserstatus.inc.php b/public/include/pages/api/getuserstatus.inc.php
new file mode 100644
index 00000000..c91ade94
--- /dev/null
+++ b/public/include/pages/api/getuserstatus.inc.php
@@ -0,0 +1,29 @@
+checkApiKey($_REQUEST['api_key']);
+
+// We have to check if that user is admin too
+if ( ! $user->isAdmin($id) ) {
+ header("HTTP/1.1 401 Unauthorized");
+ die("Access denied");
+}
+
+// Is it a username or a user ID
+ctype_digit($_REQUEST['id']) ? $username = $user->getUserName($_REQUEST['id']) : $username = $_REQUEST['id'];
+ctype_digit($_REQUEST['id']) ? $id = $_REQUEST['id'] : $id = $user->getUserId($_REQUEST['id']);
+
+// Output JSON format
+echo json_encode(array('getuserstatus' => array(
+ 'username' => $username,
+ 'shares' => $statistics->getUserShares($id),
+ 'hashrate' => $statistics->getUserHashrate($id)
+)));
+
+// Supress master template
+$supress_master = 1;
+?>
From 64d8d8abf32c9a89ca1039df3eff1358e9b639f8 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 21:37:14 +0200
Subject: [PATCH 039/168] Adding support for PPS payout method
This commit changed a few things in the backend and classes code:
* Any _PPS transaction does NOT need to be confirmed
* Queries updated for added _PPS transactions
* Template updated to properly display these transactions
Cronjob
* Added pps_payput cron to run payouts based on worker submitted shares
* **IMPORTANT**: Can NOT be run with proportional_payout!
Addresses #70
---
cronjobs/pps_payout.php | 87 +++++++++++++++++++
public/include/classes/share.class.php | 15 ++++
public/include/classes/transaction.class.php | 18 ++--
.../mmcFE/account/transactions/default.tpl | 5 +-
4 files changed, 118 insertions(+), 7 deletions(-)
create mode 100755 cronjobs/pps_payout.php
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
new file mode 100755
index 00000000..a71c42a3
--- /dev/null
+++ b/cronjobs/pps_payout.php
@@ -0,0 +1,87 @@
+#!/usr/bin/php
+can_connect() === true ){
+ $dDifficulty = $bitcoin->getdifficulty();
+} else {
+ verbose("Aborted: " . $bitcoin->can_connect() . "\n");
+ exit(1);
+}
+
+// Value per share calculation
+$pps_value = 50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']);
+
+// Find our last share accounted and last inserted share for PPS calculations
+$iPreviousShareId = $setting->getValue('pps_last_share_id');
+$iLastShareId = $share->getLastInsertedShareId();
+
+// Check for all new shares, we start one higher as our last accounted share to avoid duplicates
+$aAccountShares = $share->getSharesForAccounts($iPreviousShareId + 1, $iLastShareId);
+
+verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\t\tStatus\n");
+
+foreach ($aAccountShares as $aData) {
+ // Take our valid shares and multiply by per share value
+ $aData['payout'] = $aData['valid'] * $pps_value;
+
+ // Defaults
+ $aData['fee' ] = 0;
+ $aData['donation'] = 0;
+
+ // Calculate block fees
+ if ($config['fees'] > 0)
+ $aData['fee'] = number_format(round($config['fees'] / 100 * $aData['payout'], 8), 8);
+ // Calculate donation amount
+ $aData['donation'] = number_format(round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8), 8);
+
+ verbose($aData['id'] . "\t" .
+ $aData['username'] . "\t" .
+ $aData['invalid'] . "\t" .
+ $aData['valid'] . "\t*\t" .
+ $pps_value . "\t=\t" .
+ $aData['payout'] . "\t" .
+ $aData['donation'] . "\t" .
+ $aData['fee'] . "\t");
+
+ $strStatus = "OK";
+ // Add new credit transaction
+ if (!$transaction->addTransaction($aData['id'], $aData['payout'], 'Credit_PPS'))
+ $strStatus = "Transaction Failed";
+ // Add new fee debit for this block
+ if ($aData['fee'] > 0 && $config['fees'] > 0)
+ if (!$transaction->addTransaction($aData['id'], $aData['fee'], 'Fee_PPS'))
+ $strStatus = "Fee Failed";
+ // Add new donation debit
+ if ($aData['donation'] > 0)
+ if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation_PPS'))
+ $strStatus = "Donation Failed";
+ verbose($strStatus . "\n");
+}
+
+// Store our last inserted ID for the next run
+$setting->setValue('pps_last_share_id', $iLastShareId);
+
+verbose("\n\n------------------------------------------------------------------------------------\n\n");
+?>
diff --git a/public/include/classes/share.class.php b/public/include/classes/share.class.php
index b0a3b249..1033f92c 100644
--- a/public/include/classes/share.class.php
+++ b/public/include/classes/share.class.php
@@ -44,6 +44,21 @@ class Share {
return $this->table;
}
+ /**
+ * Get last inserted Share ID from Database
+ * Used for PPS calculations without moving to archive
+ **/
+ public function getLastInsertedShareId() {
+ $stmt = $this->mysqli->prepare("
+ SELECT MAX(id) AS id FROM $this->table
+ ");
+ if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_object()->id;
+ // Catchall
+ $this->setErrorMessage('Failed to fetch last inserted share ID');
+ return false;
+ }
+
/**
* Get all valid shares for this round
* @param previous_upstream int Previous found share accepted by upstream to limit results
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index 020140d3..711e893f 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -142,7 +142,7 @@ class Transaction {
(
SELECT sum(t.amount) AS credit
FROM $this->table AS t
- WHERE t.type = 'Credit'
+ WHERE t.type IN ('Credit', 'Credit_PPS')
) AS t1,
(
SELECT sum(t.amount) AS debit
@@ -152,7 +152,7 @@ class Transaction {
(
SELECT sum(t.amount) AS other
FROM " . $this->table . " AS t
- WHERE t.type IN ('Donation','Fee')
+ WHERE t.type IN ('Donation','Fee','Donation_PPS','Fee_PPS')
) AS t3");
if ($this->checkStmt($stmt) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
return $dBalance;
@@ -176,8 +176,11 @@ class Transaction {
SELECT sum(t.amount) AS credit
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type = 'Credit'
- AND b.confirmations >= ?
+ WHERE
+ (
+ ( t.type = 'Credit' AND b.confirmations >= ? ) OR
+ ( t.type = 'Credit_PPS' )
+ )
AND t.account_id = ?
) AS t1,
(
@@ -190,8 +193,11 @@ class Transaction {
SELECT sum(t.amount) AS other
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type IN ('Donation','Fee')
- AND b.confirmations >= ?
+ WHERE
+ (
+ ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
+ ( t.type IN ('Donation_PPS', 'Fee_PPS') )
+ )
AND t.account_id = ?
) AS t3
");
diff --git a/public/templates/mmcFE/account/transactions/default.tpl b/public/templates/mmcFE/account/transactions/default.tpl
index 8f5282e1..dd31723f 100644
--- a/public/templates/mmcFE/account/transactions/default.tpl
+++ b/public/templates/mmcFE/account/transactions/default.tpl
@@ -18,6 +18,9 @@
($TRANSACTIONS[transaction].type == 'Credit' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Donation' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Fee' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
+ or $TRANSACTIONS[transaction].type == 'Credit_PPS'
+ or $TRANSACTIONS[transaction].type == 'Fee_PPS'
+ or $TRANSACTIONS[transaction].type == 'Donation_PPS'
or $TRANSACTIONS[transaction].type == 'Debit_AP'
or $TRANSACTIONS[transaction].type == 'Debit_MP'
)}
@@ -27,7 +30,7 @@
{$TRANSACTIONS[transaction].type}
{$TRANSACTIONS[transaction].coin_address}
{if $TRANSACTIONS[transaction].height == 0}n/a{else}{$TRANSACTIONS[transaction].height}{/if}
- {$TRANSACTIONS[transaction].amount}
+ {$TRANSACTIONS[transaction].amount}
{/if}
{/section}
From 6a8979d20bc9d7dc0cf9bf64bfc85c3a09bdb775 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:23:54 +0200
Subject: [PATCH 040/168] Fixing critical issue with manual- and autopayouts
This is a proposed fix for #128:
* Mark auto_payout running via DB setting, unlock when done
* Just before actually sending money, check for running cron
Please refer to the ticket for details
---
cronjobs/auto_payout.php | 8 ++++++++
public/include/pages/account/edit.inc.php | 7 ++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/cronjobs/auto_payout.php b/cronjobs/auto_payout.php
index 68b60aa4..36c8a873 100755
--- a/cronjobs/auto_payout.php
+++ b/cronjobs/auto_payout.php
@@ -27,6 +27,9 @@ if ($bitcoin->can_connect() !== true) {
exit(1);
}
+// Mark this job as active
+$setting->setValue('auto_payout_active', 1);
+
// Fetch all users with setup AP
$users = $user->getAllAutoPayout();
@@ -69,3 +72,8 @@ if (! empty($users)) {
} else {
verbose("No user has configured their AP > 0\n");
}
+
+// Mark this job as inactive
+$setting->setValue('auto_payout_active', 0);
+
+?>
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index 84937115..1e2941bb 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -28,7 +28,12 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
if ($continue == true) {
// Send balance to address, mind 0.1 fee for transaction!
try {
- $bitcoin->sendtoaddress($sCoinAddress, $dBalance);
+ if ($setting->getValue('auto_payout_active') == 0) {
+ $bitcoin->sendtoaddress($sCoinAddress, $dBalance);
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Auto-payout active, please contact site support immidiately to revoke invalid transactions.', 'TYPE' => 'errormsg');
+ $continue = false;
+ }
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send LTC, please contact site support immidiately', 'TYPE' => 'errormsg');
$continue = false;
From a3ddf0cfcca9b80a1e3e4d4c434f53fe1653eb6a Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:31:35 +0200
Subject: [PATCH 041/168] properly format payout and round it
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index a71c42a3..1dafa288 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -44,7 +44,7 @@ verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
- $aData['payout'] = $aData['valid'] * $pps_value;
+ $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8));
// Defaults
$aData['fee' ] = 0;
From ad6051df1c0682addb4edebca39c414edee99b15 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:34:02 +0200
Subject: [PATCH 042/168] forgot 8 decimals
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index 1dafa288..bef78f2a 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -44,7 +44,7 @@ verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
- $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8));
+ $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8), 8);
// Defaults
$aData['fee' ] = 0;
From 663c427d4adaf8d96d51e98024c1dd19e83187e4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:45:53 +0200
Subject: [PATCH 043/168] properly format pps value to 12 digits
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index bef78f2a..e2804595 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -31,7 +31,7 @@ if ( $bitcoin->can_connect() === true ){
}
// Value per share calculation
-$pps_value = 50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']);
+$pps_value = number_format(round(50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']), 12) ,12);
// Find our last share accounted and last inserted share for PPS calculations
$iPreviousShareId = $setting->getValue('pps_last_share_id');
From 87e721edb89429c2d96af17858d83e8712e9339d Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:48:09 +0200
Subject: [PATCH 044/168] moved table header to the left
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index e2804595..427035d5 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -40,7 +40,7 @@ $iLastShareId = $share->getLastInsertedShareId();
// Check for all new shares, we start one higher as our last accounted share to avoid duplicates
$aAccountShares = $share->getSharesForAccounts($iPreviousShareId + 1, $iLastShareId);
-verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\t\tStatus\n");
+verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\tPayout\t\tDonation\tFee\t\tStatus\n");
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
From 84f48efa41cd81ed5c4b7e1cb03457509fd5630c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 00:51:25 +0200
Subject: [PATCH 045/168] minor template update for contributor hashrates
---
.../mmcFE/statistics/pool/contributors_hashrate.tpl | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
index b97c1515..232a5ab0 100644
--- a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
+++ b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
@@ -13,11 +13,12 @@
{assign var=rank value=1}
{assign var=listed value=0}
{section contrib $CONTRIBHASHES}
+ {math assign="estday" equation="round(reward / ( diff * pow(2,32) / ( hashrate * 1000 ) / 3600 / 24), 3)" diff=$DIFFICULTY reward=$REWARD hashrate=$CONTRIBHASHES[contrib].hashrate}
{$rank++}
{$CONTRIBHASHES[contrib].account}
{$CONTRIBHASHES[contrib].hashrate|number_format}
- {math equation="round(reward / ( diff * pow(2,32) / ( hashrate * 1000 ) / 3600 / 24), 3)" diff=$DIFFICULTY reward=$REWARD hashrate=$CONTRIBHASHES[contrib].hashrate}
+ {$estday|number_format:"3"}
{/section}
{if $listed != 1}
@@ -25,7 +26,7 @@
n/a
{$GLOBAL.userdata.username}
{$GLOBAL.userdata.hashrate}
- {math equation="round(reward / ( diff * pow(2,32) / ( hashrate * 1000 ) / 3600 / 24), 3)" diff=$DIFFICULTY reward=$REWARD hashrate=$GLOBAL.userdata.hashrate}
+ {$estday|number_format:"3"}
{/if}
From 1046bd113de324ea6a6f5434a7e787c8b610e0d1 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 00:54:24 +0200
Subject: [PATCH 046/168] minor template update for contributor shares
---
public/templates/mmcFE/statistics/pool/contributors_shares.tpl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/templates/mmcFE/statistics/pool/contributors_shares.tpl b/public/templates/mmcFE/statistics/pool/contributors_shares.tpl
index 04e9c3e0..444effa4 100644
--- a/public/templates/mmcFE/statistics/pool/contributors_shares.tpl
+++ b/public/templates/mmcFE/statistics/pool/contributors_shares.tpl
@@ -22,7 +22,7 @@
n/a
{$GLOBAL.userdata.username}
- {$GLOBAL.userdata.shares.valid}
+ {$GLOBAL.userdata.shares.valid|number_format}
{/if}
From f63485a53939333ae7ce2a1f7de960683ece890d Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 08:33:14 +0200
Subject: [PATCH 047/168] Fixing admin panel user display
* Fixes #130. Removed total shares in favor of the hashrate.
* Fixes hashrate display.
* Added pagination template file to include pagination on other pages in
the future.
---
public/include/classes/statistics.class.php | 2 +-
public/templates/mmcFE/admin/user/default.tpl | 21 ++-----------------
public/templates/mmcFE/global/pagination.tpl | 15 +++++++++++++
3 files changed, 18 insertions(+), 20 deletions(-)
create mode 100644 public/templates/mmcFE/global/pagination.tpl
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index 4ed74bb4..f3924f13 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -189,13 +189,13 @@ class Statistics {
a.username AS username,
a.donate_percent AS donate_percent,
a.email AS email,
- COUNT(s.id) AS shares,
ROUND(COUNT(s.id) * POW(2," . $this->config['difficulty'] . ") / 600 / 1000,2) AS hashrate
FROM " . $this->user->getTableName() . " AS a
LEFT JOIN " . $this->share->getTableName() . " AS s
ON a.username = SUBSTRING_INDEX( s.username, '.', 1 )
WHERE
a.username LIKE ?
+ AND s.time > DATE_SUB(now(), INTERVAL 10 MINUTE)
GROUP BY username
ORDER BY username
");
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 5386a84f..92809395 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -9,21 +9,7 @@
{include file="global/block_header.tpl" BLOCK_HEADER="User Information"}
-
+{include file="global/pagination.tpl"}
@@ -32,7 +18,6 @@
Username
E-Mail
Hashrate
- Shares
Est. Donation
Est. Payout
Balance
@@ -45,8 +30,7 @@
{$USERS[user].id}
{$USERS[user].username}
{$USERS[user].email}
- {$USERS[user].hashrate / 1024}
- {$USERS[user].shares}
+ {$USERS[user].hashrate}
{$USERS[user].payout.est_donation|number_format:"8"}
{$USERS[user].payout.est_payout|number_format:"8"}
{$USERS[user].balance|number_format:"8"}
@@ -66,7 +50,6 @@
Username
E-Mail
Hashrate
- Shares
Est. Donation
Est. Payout
Balance
diff --git a/public/templates/mmcFE/global/pagination.tpl b/public/templates/mmcFE/global/pagination.tpl
new file mode 100644
index 00000000..0bae6db5
--- /dev/null
+++ b/public/templates/mmcFE/global/pagination.tpl
@@ -0,0 +1,15 @@
+
From 4b05846a78eb9ac0fd321d8c6a14c0e3f20a9ff7 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 08:42:07 +0200
Subject: [PATCH 048/168] Re-Adding shares for admin user panel
* Re-enables estimations
* Still fixes #130 which had issues with hashrates, those are still
fixed
---
public/include/classes/statistics.class.php | 3 ++-
public/templates/mmcFE/admin/user/default.tpl | 3 +++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index f3924f13..b86acd72 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -189,7 +189,8 @@ class Statistics {
a.username AS username,
a.donate_percent AS donate_percent,
a.email AS email,
- ROUND(COUNT(s.id) * POW(2," . $this->config['difficulty'] . ") / 600 / 1000,2) AS hashrate
+ ROUND(COUNT(s.id) * POW(2," . $this->config['difficulty'] . ") / 600 / 1000,2) AS hashrate,
+ ( SELECT COUNT(id) FROM " . $this->share->getTableName() . " WHERE a.username = SUBSTRING_INDEX( s.username, '.', 1 ) ) AS shares
FROM " . $this->user->getTableName() . " AS a
LEFT JOIN " . $this->share->getTableName() . " AS s
ON a.username = SUBSTRING_INDEX( s.username, '.', 1 )
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 92809395..86c52e48 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -17,6 +17,7 @@
ID
Username
E-Mail
+ Shares
Hashrate
Est. Donation
Est. Payout
@@ -30,6 +31,7 @@
{$USERS[user].id}
{$USERS[user].username}
{$USERS[user].email}
+ {$USERS[user].shares}
{$USERS[user].hashrate}
{$USERS[user].payout.est_donation|number_format:"8"}
{$USERS[user].payout.est_payout|number_format:"8"}
@@ -49,6 +51,7 @@
ID
Username
E-Mail
+ Shares
Hashrate
Est. Donation
Est. Payout
From 671a2d01cada9a72512de90963c3cafd27c6764e Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 09:02:58 +0200
Subject: [PATCH 049/168] Properly display both shares and hashrates
* As proposed in #132 thi allows for both shares and hashsrates
Fixes #132.
---
public/include/classes/statistics.class.php | 6 ++----
public/include/pages/admin/user.inc.php | 1 +
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index b86acd72..a63416dd 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -189,14 +189,12 @@ class Statistics {
a.username AS username,
a.donate_percent AS donate_percent,
a.email AS email,
- ROUND(COUNT(s.id) * POW(2," . $this->config['difficulty'] . ") / 600 / 1000,2) AS hashrate,
- ( SELECT COUNT(id) FROM " . $this->share->getTableName() . " WHERE a.username = SUBSTRING_INDEX( s.username, '.', 1 ) ) AS shares
+ COUNT(s.id) AS shares
FROM " . $this->user->getTableName() . " AS a
LEFT JOIN " . $this->share->getTableName() . " AS s
ON a.username = SUBSTRING_INDEX( s.username, '.', 1 )
WHERE
- a.username LIKE ?
- AND s.time > DATE_SUB(now(), INTERVAL 10 MINUTE)
+ a.username LIKE ?
GROUP BY username
ORDER BY username
");
diff --git a/public/include/pages/admin/user.inc.php b/public/include/pages/admin/user.inc.php
index cc961f44..b6dab89b 100644
--- a/public/include/pages/admin/user.inc.php
+++ b/public/include/pages/admin/user.inc.php
@@ -21,6 +21,7 @@ if ($_POST['query']) {
// Query against the stats table? Currently cached though.
foreach ($aUsers as $iKey => $aUser) {
$aUser['balance'] = $transaction->getBalance($aUser['id']);
+ $aUser['hashrate'] = $statistics->getUserHashrate($aUser['id']);
$aUser['payout']['est_block'] = round(( (int)$aUser['shares'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
$aUser['payout']['est_fee'] = round(($config['fees'] / 100) * $aUser['payout']['est_block'], 3);
$aUser['payout']['est_donation'] = round((( $aUser['donate_percent'] / 100) * ($aUser['payout']['est_block'] - $aUser['payout']['est_fee'])), 3);
From bf225fb0de230c8425755b0abce0266e9772bf60 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 14:25:36 +0200
Subject: [PATCH 050/168] Add worker montioring to template and worker class
* Add configurable monitoring for workers into template
* Store monitoring status in DB
First commit for #116
---
public/include/classes/worker.class.php | 18 ++++++++++--------
.../mmcFE/account/workers/default.tpl | 2 ++
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/public/include/classes/worker.class.php b/public/include/classes/worker.class.php
index 5a5c19c4..6052eaac 100644
--- a/public/include/classes/worker.class.php
+++ b/public/include/classes/worker.class.php
@@ -43,17 +43,19 @@ class Worker {
public function updateWorkers($account_id, $data) {
$this->debug->append("STA " . __METHOD__, 4);
$username = $this->user->getUserName($account_id);
+ $iFailed = 0;
foreach ($data as $key => $value) {
// Prefix the WebUser to Worker name
$value['username'] = "$username." . $value['username'];
- $stmt = $this->mysqli->prepare("UPDATE $this->table SET password = ?, username = ? WHERE account_id = ? AND id = ?");
- if ($this->checkStmt($stmt)) {
- if (!$stmt->bind_param('ssii', $value['password'], $value['username'], $account_id, $key)) return false;
- if (!$stmt->execute()) return false;
- $stmt->close();
- }
+ $stmt = $this->mysqli->prepare("UPDATE $this->table SET password = ?, username = ?, monitor = ? WHERE account_id = ? AND id = ?");
+ if ( ! ( $this->checkStmt($stmt) && $stmt->bind_param('ssiii', $value['password'], $value['username'], $value['monitor'], $account_id, $key) && $stmt->execute()) )
+ $iFailed++;
}
- return true;
+ if ($iFailed == 0)
+ return true;
+ // Catchall
+ $this->setErrorMessage('Failed to update ' . $iFailed . ' worker.');
+ return false;
}
/**
@@ -64,7 +66,7 @@ class Worker {
public function getWorkers($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
- SELECT id, username, password,
+ SELECT id, username, password, monitor,
( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS active,
( SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS hashrate
FROM $this->table
diff --git a/public/templates/mmcFE/account/workers/default.tpl b/public/templates/mmcFE/account/workers/default.tpl
index f1b6e875..612bd227 100644
--- a/public/templates/mmcFE/account/workers/default.tpl
+++ b/public/templates/mmcFE/account/workers/default.tpl
@@ -10,6 +10,7 @@
Worker Name
Password
Active
+ Monitor
Khash/s
@@ -20,6 +21,7 @@
{$username.0|escape}.
+
{$WORKERS[worker].hashrate|number_format}
Delete
From d7e65c7b3797a15d7bc3fbd86ab23852989a2961 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 14:42:29 +0200
Subject: [PATCH 051/168] Progress on notifications
* Added main mail class
* notification class extends mail class
* Added mail template for IDLE workers
* Added notification table to SQL structure
This works already but once notified the status is not reset as soon as
a worker is active again. Need to think of a system to do that
automatically.
Addresses #116
---
cronjobs/notifications.php | 42 ++++++++++++++
public/include/autoloader.inc.php | 2 +
public/include/classes/mail.class.php | 58 +++++++++++++++++++
public/include/classes/notification.class.php | 45 ++++++++++++++
public/include/classes/worker.class.php | 20 +++++++
public/templates/mail/idle_worker.tpl | 9 +++
sql/mmcfe_ng_structure.sql | 20 ++++++-
7 files changed, 193 insertions(+), 3 deletions(-)
create mode 100755 cronjobs/notifications.php
create mode 100644 public/include/classes/mail.class.php
create mode 100644 public/include/classes/notification.class.php
create mode 100644 public/templates/mail/idle_worker.tpl
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
new file mode 100755
index 00000000..7bca08ec
--- /dev/null
+++ b/cronjobs/notifications.php
@@ -0,0 +1,42 @@
+#!/usr/bin/php
+getAllIdleWorkers();
+if (empty($aWorkers)) {
+ verbose("No idle workers found\n");
+ exit;
+}
+
+foreach ($aWorkers as $aWorker) {
+ $aData = $aWorker;
+ $aData['username'] = $user->getUserName($aWorker['account_id']);
+ $aData['email'] = $user->getUserEmail($aData['username']);
+ if (!$notification->isNotified($aData)) {
+ if (!$notification->addNotification('idle_worker', $aData) && $notification->sendMail('sebastian@grewe.ca', 'idle_worker', $aData))
+ verbose("Unable to send notification: " . $notification->getError() . "\n");
+ } else {
+ verbose("Already notified for this worker\n");
+ }
+}
+?>
diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php
index ea16564e..a78d4a62 100644
--- a/public/include/autoloader.inc.php
+++ b/public/include/autoloader.inc.php
@@ -14,3 +14,5 @@ require_once(CLASS_DIR . '/worker.class.php');
require_once(CLASS_DIR . '/statistics.class.php');
require_once(CLASS_DIR . '/transaction.class.php');
require_once(CLASS_DIR . '/setting.class.php');
+require_once(CLASS_DIR . '/mail.class.php');
+require_once(CLASS_DIR . '/notification.class.php');
diff --git a/public/include/classes/mail.class.php b/public/include/classes/mail.class.php
new file mode 100644
index 00000000..6c7cc0f1
--- /dev/null
+++ b/public/include/classes/mail.class.php
@@ -0,0 +1,58 @@
+debug = $debug;
+ }
+ public function setMysql($mysqli) {
+ $this->mysqli = $mysqli;
+ }
+ public function setSmarty($smarty) {
+ $this->smarty = $smarty;
+ }
+ public function setConfig($config) {
+ $this->config = $config;
+ }
+
+ private function checkStmt($bState) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ if ($bState ===! true) {
+ $this->debug->append("Failed to prepare statement: " . $this->mysqli->error);
+ $this->setErrorMessage('Internal application Error');
+ return false;
+ }
+ return true;
+ }
+
+ public function sendMail($email, $template, $vars) {
+ $this->smarty->assign('WEBSITENAME', $this->config['website']['name']);
+ $headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
+ $headers .= "MIME-Version: 1.0\n";
+ $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
+ if (mail($email,
+ $this->smarty->fetch(BASEPATH . 'templates/mail/subject.tpl'),
+ $this->smarty->fetch(BASEPATH . 'templates/mail/' . $template . '.tpl'),
+ $headers)) {
+ return true;
+ } else {
+ $this->setErrorMessage("Unable to send mail");
+ return false;
+ }
+ return false;
+ }
+}
+
+// Make our class available automatically
+$mail = new Mail ();
+$mail->setDebug($debug);
+$mail->setMysql($mysqli);
+$mail->setSmarty($smarty);
+$mail->setConfig($config);
+
+?>
diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php
new file mode 100644
index 00000000..a9eca1af
--- /dev/null
+++ b/public/include/classes/notification.class.php
@@ -0,0 +1,45 @@
+mysqli->prepare("SELECT id FROM $this->table WHERE data = ? LIMIT 1");
+ if ($stmt && $stmt->bind_param('s', $data) && $stmt->execute() && $stmt->store_result() && $stmt->num_rows == 1)
+ return true;
+ // Catchall
+ // Does not seem to have a notification set
+ return false;
+ }
+
+ /**
+ * Add a new notification to the table
+ * @param type string Type of the notification
+ * @return bool
+ **/
+ public function addNotification($type, $data) {
+ // Store notification data as json
+ $data = json_encode($data);
+ $stmt = $this->mysqli->prepare("INSERT INTO $this->table (type, data) VALUES (?,?)");
+ if ($stmt && $stmt->bind_param('ss', $type, $data) && $stmt->execute())
+ return true;
+ $this->debug->append("Failed to add notification for $type with $data: " . $this->mysqli->error);
+ $this->setErrorMessage("Unable to add new notification");
+ return false;
+ }
+}
+
+$notification = new Notification();
+$notification->setDebug($debug);
+$notification->setMysql($mysqli);
+$notification->setSmarty($smarty);
+$notification->setConfig($config);
diff --git a/public/include/classes/worker.class.php b/public/include/classes/worker.class.php
index 6052eaac..a5052ba9 100644
--- a/public/include/classes/worker.class.php
+++ b/public/include/classes/worker.class.php
@@ -58,6 +58,26 @@ class Worker {
return false;
}
+ /**
+ * Fetch all IDLE workers that have monitoring enabled
+ * @param none
+ * @return data array Workers in IDLE state and monitoring enabled
+ **/
+ public function getAllIdleWorkers() {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("
+ SELECT account_id, id, username
+ FROM " . $this->table . "
+ WHERE monitor = 1 AND ( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) = 0");
+
+ if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_all(MYSQLI_ASSOC);
+ // Catchall
+ $this->setErrorMessage("Unable to fetch IDLE, monitored workers");
+ echo $this->mysqli->error;
+ return false;
+ }
+
/**
* Fetch all workers for an account
* @param account_id int User ID
diff --git a/public/templates/mail/idle_worker.tpl b/public/templates/mail/idle_worker.tpl
new file mode 100644
index 00000000..a21aaac3
--- /dev/null
+++ b/public/templates/mail/idle_worker.tpl
@@ -0,0 +1,9 @@
+
+
+One of your workers is currently IDLE.
+Since monitoring is enabled for this worker, this notification was sent.
+Please check your workers!
+
+
+
+
diff --git a/sql/mmcfe_ng_structure.sql b/sql/mmcfe_ng_structure.sql
index c3c626bd..a971d455 100644
--- a/sql/mmcfe_ng_structure.sql
+++ b/sql/mmcfe_ng_structure.sql
@@ -3,7 +3,7 @@
-- http://www.phpmyadmin.net
--
-- Host: localhost
--- Generation Time: Jun 06, 2013 at 09:01 PM
+-- Generation Time: Jun 07, 2013 at 02:42 PM
-- Server version: 5.5.31-0ubuntu0.13.04.1
-- PHP Version: 5.4.9-4ubuntu2
@@ -69,6 +69,20 @@ CREATE TABLE IF NOT EXISTS `blocks` (
-- --------------------------------------------------------
+--
+-- Table structure for table `notifications`
+--
+
+CREATE TABLE IF NOT EXISTS `notifications` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `type` varchar(25) NOT NULL,
+ `data` text NOT NULL,
+ `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
--
-- Table structure for table `pool_worker`
--
@@ -136,7 +150,7 @@ CREATE TABLE IF NOT EXISTS `shares_archive` (
PRIMARY KEY (`id`),
UNIQUE KEY `share_id` (`share_id`),
KEY `time` (`time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
-- --------------------------------------------------------
@@ -153,7 +167,7 @@ CREATE TABLE IF NOT EXISTS `statistics_shares` (
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`),
KEY `block_id` (`block_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
From 4966f64a5912698694297d3a9738575d05999af3 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 15:07:26 +0200
Subject: [PATCH 052/168] Adding notification reset once worker is active
Go through all active notifications (active means they are not notified
again) and check if their state has changed. If so, mark as inactive and
allow for re-notification of the same type and data.
---
cronjobs/notifications.php | 34 +++++++++++------
public/include/classes/mail.class.php | 2 +-
public/include/classes/notification.class.php | 38 ++++++++++++++++++-
public/include/classes/worker.class.php | 21 ++++++++++
4 files changed, 80 insertions(+), 15 deletions(-)
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
index 7bca08ec..e70d2b07 100755
--- a/cronjobs/notifications.php
+++ b/cronjobs/notifications.php
@@ -22,21 +22,31 @@ limitations under the License.
// Include all settings and classes
require_once('shared.inc.php');
+// Find all IDLE workers
$aWorkers = $worker->getAllIdleWorkers();
if (empty($aWorkers)) {
verbose("No idle workers found\n");
- exit;
-}
-
-foreach ($aWorkers as $aWorker) {
- $aData = $aWorker;
- $aData['username'] = $user->getUserName($aWorker['account_id']);
- $aData['email'] = $user->getUserEmail($aData['username']);
- if (!$notification->isNotified($aData)) {
- if (!$notification->addNotification('idle_worker', $aData) && $notification->sendMail('sebastian@grewe.ca', 'idle_worker', $aData))
- verbose("Unable to send notification: " . $notification->getError() . "\n");
- } else {
- verbose("Already notified for this worker\n");
+} else {
+ foreach ($aWorkers as $aWorker) {
+ $aData = $aWorker;
+ $aData['username'] = $user->getUserName($aWorker['account_id']);
+ $aData['email'] = $user->getUserEmail($aData['username']);
+ if (!$notification->isNotified($aData)) {
+ if (!$notification->addNotification('idle_worker', $aData) && $notification->sendMail('sebastian@grewe.ca', 'idle_worker', $aData))
+ verbose("Unable to send notification: " . $notification->getError() . "\n");
+ } else {
+ verbose("Already notified for this worker\n");
+ }
}
}
+// We notified, lets check which recovered
+$aNotifications = $notification->getAllActive();
+foreach ($aNotifications as $aNotification) {
+ $aData = json_decode($aNotification['data'], true);
+ $aWorker = $worker->getWorker($aData['id']);
+ if ($aWorker['active'] == 1)
+ if (!$notification->setInactive($aNotification['id']))
+ verbose("Failed to set notification inactive for " . $aWorker['username'] . "\n");
+}
+
?>
diff --git a/public/include/classes/mail.class.php b/public/include/classes/mail.class.php
index 6c7cc0f1..a1cf2137 100644
--- a/public/include/classes/mail.class.php
+++ b/public/include/classes/mail.class.php
@@ -20,7 +20,7 @@ class Mail {
$this->config = $config;
}
- private function checkStmt($bState) {
+ function checkStmt($bState) {
$this->debug->append("STA " . __METHOD__, 4);
if ($bState ===! true) {
$this->debug->append("Failed to prepare statement: " . $this->mysqli->error);
diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php
index a9eca1af..9a6dcf3b 100644
--- a/public/include/classes/notification.class.php
+++ b/public/include/classes/notification.class.php
@@ -7,13 +7,36 @@ if (!defined('SECURITY'))
class Notification extends Mail {
var $table = 'notifications';
+ public function setInactive($id) {
+ $field = array(
+ 'name' => 'active',
+ 'type' => 'i',
+ 'value' => 0
+ );
+ return $this->updateSingle($id, $field);
+ }
+
+ /**
+ * Update a single row in a table
+ * @param userID int Account ID
+ * @param field string Field to update
+ * @return bool
+ **/
+ private function updateSingle($id, $field) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("UPDATE $this->table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1");
+ if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute())
+ return true;
+ $this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id");
+ return false;
+ }
/**
* We check our notification table for existing data
* so we can avoid duplicate entries
**/
public function isNotified($aData) {
$data = json_encode($aData);
- $stmt = $this->mysqli->prepare("SELECT id FROM $this->table WHERE data = ? LIMIT 1");
+ $stmt = $this->mysqli->prepare("SELECT id FROM $this->table WHERE data = ? AND active = 1 LIMIT 1");
if ($stmt && $stmt->bind_param('s', $data) && $stmt->execute() && $stmt->store_result() && $stmt->num_rows == 1)
return true;
// Catchall
@@ -21,6 +44,17 @@ class Notification extends Mail {
return false;
}
+ /**
+ * Get all active notifications
+ **/
+ public function getAllActive() {
+ $stmt =$this->mysqli->prepare("SELECT id, data FROM $this->table WHERE active = 1 LIMIT 1");
+ if ($stmt && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_all(MYSQLI_ASSOC);
+ // Catchall
+ return false;
+ }
+
/**
* Add a new notification to the table
* @param type string Type of the notification
@@ -29,7 +63,7 @@ class Notification extends Mail {
public function addNotification($type, $data) {
// Store notification data as json
$data = json_encode($data);
- $stmt = $this->mysqli->prepare("INSERT INTO $this->table (type, data) VALUES (?,?)");
+ $stmt = $this->mysqli->prepare("INSERT INTO $this->table (type, data, active) VALUES (?,?,1)");
if ($stmt && $stmt->bind_param('ss', $type, $data) && $stmt->execute())
return true;
$this->debug->append("Failed to add notification for $type with $data: " . $this->mysqli->error);
diff --git a/public/include/classes/worker.class.php b/public/include/classes/worker.class.php
index a5052ba9..6a9f6524 100644
--- a/public/include/classes/worker.class.php
+++ b/public/include/classes/worker.class.php
@@ -78,6 +78,27 @@ class Worker {
return false;
}
+ /**
+ * Fetch a specific worker and its status
+ * @param id int Worker ID
+ * @return mixed array Worker details
+ **/
+ public function getWorker($id) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("
+ SELECT id, username, password, monitor,
+ ( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS active,
+ ( SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS hashrate
+ FROM $this->table
+ WHERE id = ?
+ ");
+ if ($this->checkStmt($stmt) && $stmt->bind_param('i', $id) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_assoc();
+ // Catchall
+ echo $this->mysqli->error;
+ return false;
+ }
+
/**
* Fetch all workers for an account
* @param account_id int User ID
From 432540335fd966ee000b385b5082fa3e71a59be1 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 15:35:58 +0200
Subject: [PATCH 053/168] Working notification system
* Added things to mail templates
* Modified user password reset call for new mail template
* Added BASEPATH to smarty code to ensure templates are compiled in the
proper directory
* Updated mail and notification class
* Updated notification cron
* Added notification cron to run-cron list
---
cronjobs/notifications.php | 23 +++++++++++++------
cronjobs/run-crons.sh | 2 +-
public/include/classes/mail.class.php | 11 +++++++--
public/include/classes/notification.class.php | 1 +
public/include/classes/user.class.php | 1 +
public/include/smarty.inc.php | 6 ++---
public/templates/mail/idle_worker.tpl | 2 +-
public/templates/mail/subject.tpl | 2 +-
8 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
index e70d2b07..45bda82a 100755
--- a/cronjobs/notifications.php
+++ b/cronjobs/notifications.php
@@ -30,23 +30,32 @@ if (empty($aWorkers)) {
foreach ($aWorkers as $aWorker) {
$aData = $aWorker;
$aData['username'] = $user->getUserName($aWorker['account_id']);
+ $aData['subject'] = 'IDLE Worker : ' . $aWorker['username'];
$aData['email'] = $user->getUserEmail($aData['username']);
- if (!$notification->isNotified($aData)) {
- if (!$notification->addNotification('idle_worker', $aData) && $notification->sendMail('sebastian@grewe.ca', 'idle_worker', $aData))
- verbose("Unable to send notification: " . $notification->getError() . "\n");
- } else {
- verbose("Already notified for this worker\n");
+ if ( $notification->isNotified($aData) ) {
+ verbose("Worker already notified\n");
+ continue;
}
+ if ($notification->addNotification('idle_worker', $aData) && $notification->sendMail($aData['email'], 'idle_worker', $aData)) {
+ verbose ("Notified " . $aData['email'] . " for IDLE worker " . $aWorker['username'] . "\n");
+ } else {
+ verbose("Unable to send notification: " . $notification->getError() . "\n");
+ }
}
}
+
// We notified, lets check which recovered
$aNotifications = $notification->getAllActive();
foreach ($aNotifications as $aNotification) {
$aData = json_decode($aNotification['data'], true);
$aWorker = $worker->getWorker($aData['id']);
- if ($aWorker['active'] == 1)
- if (!$notification->setInactive($aNotification['id']))
+ if ($aWorker['active'] == 1) {
+ if ($notification->setInactive($aNotification['id'])) {
+ verbose("Marked notification " . $aNotification['id'] . " as inactive\n");
+ } else {
verbose("Failed to set notification inactive for " . $aWorker['username'] . "\n");
+ }
+ }
}
?>
diff --git a/cronjobs/run-crons.sh b/cronjobs/run-crons.sh
index 730a9063..5f9179dc 100755
--- a/cronjobs/run-crons.sh
+++ b/cronjobs/run-crons.sh
@@ -16,7 +16,7 @@ PIDFILE='/tmp/mmcfe-ng-cron.pid'
CRONHOME='.'
# List of cruns to execute
-CRONS="findblock.php proportional_payout.php blockupdate.php auto_payout.php tickerupdate.php"
+CRONS="findblock.php proportional_payout.php blockupdate.php auto_payout.php tickerupdate.php notifications.php"
# Additional arguments to pass to cronjobs
CRONARGS="-v"
diff --git a/public/include/classes/mail.class.php b/public/include/classes/mail.class.php
index a1cf2137..2800500c 100644
--- a/public/include/classes/mail.class.php
+++ b/public/include/classes/mail.class.php
@@ -19,7 +19,12 @@ class Mail {
public function setConfig($config) {
$this->config = $config;
}
-
+ public function setErrorMessage($msg) {
+ $this->sError = $msg;
+ }
+ public function getError() {
+ return $this->sError;
+ }
function checkStmt($bState) {
$this->debug->append("STA " . __METHOD__, 4);
if ($bState ===! true) {
@@ -30,8 +35,10 @@ class Mail {
return true;
}
- public function sendMail($email, $template, $vars) {
+ public function sendMail($email, $template, $aData) {
$this->smarty->assign('WEBSITENAME', $this->config['website']['name']);
+ $this->smarty->assign('SUBJECT', $aData['subject']);
+ $this->smarty->assign('DATA', $aData);
$headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php
index 9a6dcf3b..983db437 100644
--- a/public/include/classes/notification.class.php
+++ b/public/include/classes/notification.class.php
@@ -41,6 +41,7 @@ class Notification extends Mail {
return true;
// Catchall
// Does not seem to have a notification set
+ $this->setErrorMessage("Unable to run query: " . $this->mysqli->error);
return false;
}
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 8db17a1e..b4627729 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -486,6 +486,7 @@ class User {
}
$smarty->assign('TOKEN', $token);
$smarty->assign('USERNAME', $username);
+ $smarty->assign('SUBJECT', 'Password Reset Request');
$smarty->assign('WEBSITENAME', $this->config['website']['name']);
$headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
$headers .= "MIME-Version: 1.0\n";
diff --git a/public/include/smarty.inc.php b/public/include/smarty.inc.php
index b2e67f37..5668e1d3 100644
--- a/public/include/smarty.inc.php
+++ b/public/include/smarty.inc.php
@@ -16,10 +16,10 @@ $smarty = new Smarty;
// Assign our local paths
$debug->append('Define Smarty Paths', 3);
-$smarty->template_dir = 'templates/' . THEME . '/';
-$smarty->compile_dir = 'templates/compile/';
+$smarty->template_dir = BASEPATH . 'templates/' . THEME . '/';
+$smarty->compile_dir = BASEPATH . 'templates/compile/';
// Optional smarty caching, check Smarty documentation for details
$smarty->caching = $config['cache'];
-$smarty->cache_dir = "templates/cache";
+$smarty->cache_dir = BASEPATH . "templates/cache";
?>
diff --git a/public/templates/mail/idle_worker.tpl b/public/templates/mail/idle_worker.tpl
index a21aaac3..6d1c282c 100644
--- a/public/templates/mail/idle_worker.tpl
+++ b/public/templates/mail/idle_worker.tpl
@@ -1,6 +1,6 @@
-One of your workers is currently IDLE.
+One of your workers is currently IDLE: {$DATA.username}
Since monitoring is enabled for this worker, this notification was sent.
Please check your workers!
diff --git a/public/templates/mail/subject.tpl b/public/templates/mail/subject.tpl
index 665e26f5..94fd6a28 100644
--- a/public/templates/mail/subject.tpl
+++ b/public/templates/mail/subject.tpl
@@ -1 +1 @@
-[ {$WEBSITENAME} ] Password Reset Request
+[ {$WEBSITENAME} ] {$SUBJECT}
From c69fbe4fc416f93e42fd1998dc562a06830d8be0 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 14:25:36 +0200
Subject: [PATCH 054/168] Add worker montioring to template and worker class
* Add configurable monitoring for workers into template
* Store monitoring status in DB
First commit for #116
---
public/include/classes/worker.class.php | 18 ++++++++++--------
.../mmcFE/account/workers/default.tpl | 2 ++
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/public/include/classes/worker.class.php b/public/include/classes/worker.class.php
index 5a5c19c4..6052eaac 100644
--- a/public/include/classes/worker.class.php
+++ b/public/include/classes/worker.class.php
@@ -43,17 +43,19 @@ class Worker {
public function updateWorkers($account_id, $data) {
$this->debug->append("STA " . __METHOD__, 4);
$username = $this->user->getUserName($account_id);
+ $iFailed = 0;
foreach ($data as $key => $value) {
// Prefix the WebUser to Worker name
$value['username'] = "$username." . $value['username'];
- $stmt = $this->mysqli->prepare("UPDATE $this->table SET password = ?, username = ? WHERE account_id = ? AND id = ?");
- if ($this->checkStmt($stmt)) {
- if (!$stmt->bind_param('ssii', $value['password'], $value['username'], $account_id, $key)) return false;
- if (!$stmt->execute()) return false;
- $stmt->close();
- }
+ $stmt = $this->mysqli->prepare("UPDATE $this->table SET password = ?, username = ?, monitor = ? WHERE account_id = ? AND id = ?");
+ if ( ! ( $this->checkStmt($stmt) && $stmt->bind_param('ssiii', $value['password'], $value['username'], $value['monitor'], $account_id, $key) && $stmt->execute()) )
+ $iFailed++;
}
- return true;
+ if ($iFailed == 0)
+ return true;
+ // Catchall
+ $this->setErrorMessage('Failed to update ' . $iFailed . ' worker.');
+ return false;
}
/**
@@ -64,7 +66,7 @@ class Worker {
public function getWorkers($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
- SELECT id, username, password,
+ SELECT id, username, password, monitor,
( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS active,
( SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS hashrate
FROM $this->table
diff --git a/public/templates/mmcFE/account/workers/default.tpl b/public/templates/mmcFE/account/workers/default.tpl
index f1b6e875..612bd227 100644
--- a/public/templates/mmcFE/account/workers/default.tpl
+++ b/public/templates/mmcFE/account/workers/default.tpl
@@ -10,6 +10,7 @@
Worker Name
Password
Active
+ Monitor
Khash/s
@@ -20,6 +21,7 @@
{$username.0|escape}.
+
{$WORKERS[worker].hashrate|number_format}
Delete
From 9ac2dadd973d1f2d465a81cb4addaec2333bc043 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 14:42:29 +0200
Subject: [PATCH 055/168] Progress on notifications
* Added main mail class
* notification class extends mail class
* Added mail template for IDLE workers
* Added notification table to SQL structure
This works already but once notified the status is not reset as soon as
a worker is active again. Need to think of a system to do that
automatically.
Addresses #116
---
cronjobs/notifications.php | 42 ++++++++++++++
public/include/autoloader.inc.php | 2 +
public/include/classes/mail.class.php | 58 +++++++++++++++++++
public/include/classes/notification.class.php | 45 ++++++++++++++
public/include/classes/worker.class.php | 20 +++++++
public/templates/mail/idle_worker.tpl | 9 +++
sql/mmcfe_ng_structure.sql | 20 ++++++-
7 files changed, 193 insertions(+), 3 deletions(-)
create mode 100755 cronjobs/notifications.php
create mode 100644 public/include/classes/mail.class.php
create mode 100644 public/include/classes/notification.class.php
create mode 100644 public/templates/mail/idle_worker.tpl
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
new file mode 100755
index 00000000..7bca08ec
--- /dev/null
+++ b/cronjobs/notifications.php
@@ -0,0 +1,42 @@
+#!/usr/bin/php
+getAllIdleWorkers();
+if (empty($aWorkers)) {
+ verbose("No idle workers found\n");
+ exit;
+}
+
+foreach ($aWorkers as $aWorker) {
+ $aData = $aWorker;
+ $aData['username'] = $user->getUserName($aWorker['account_id']);
+ $aData['email'] = $user->getUserEmail($aData['username']);
+ if (!$notification->isNotified($aData)) {
+ if (!$notification->addNotification('idle_worker', $aData) && $notification->sendMail('sebastian@grewe.ca', 'idle_worker', $aData))
+ verbose("Unable to send notification: " . $notification->getError() . "\n");
+ } else {
+ verbose("Already notified for this worker\n");
+ }
+}
+?>
diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php
index ea16564e..a78d4a62 100644
--- a/public/include/autoloader.inc.php
+++ b/public/include/autoloader.inc.php
@@ -14,3 +14,5 @@ require_once(CLASS_DIR . '/worker.class.php');
require_once(CLASS_DIR . '/statistics.class.php');
require_once(CLASS_DIR . '/transaction.class.php');
require_once(CLASS_DIR . '/setting.class.php');
+require_once(CLASS_DIR . '/mail.class.php');
+require_once(CLASS_DIR . '/notification.class.php');
diff --git a/public/include/classes/mail.class.php b/public/include/classes/mail.class.php
new file mode 100644
index 00000000..6c7cc0f1
--- /dev/null
+++ b/public/include/classes/mail.class.php
@@ -0,0 +1,58 @@
+debug = $debug;
+ }
+ public function setMysql($mysqli) {
+ $this->mysqli = $mysqli;
+ }
+ public function setSmarty($smarty) {
+ $this->smarty = $smarty;
+ }
+ public function setConfig($config) {
+ $this->config = $config;
+ }
+
+ private function checkStmt($bState) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ if ($bState ===! true) {
+ $this->debug->append("Failed to prepare statement: " . $this->mysqli->error);
+ $this->setErrorMessage('Internal application Error');
+ return false;
+ }
+ return true;
+ }
+
+ public function sendMail($email, $template, $vars) {
+ $this->smarty->assign('WEBSITENAME', $this->config['website']['name']);
+ $headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
+ $headers .= "MIME-Version: 1.0\n";
+ $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
+ if (mail($email,
+ $this->smarty->fetch(BASEPATH . 'templates/mail/subject.tpl'),
+ $this->smarty->fetch(BASEPATH . 'templates/mail/' . $template . '.tpl'),
+ $headers)) {
+ return true;
+ } else {
+ $this->setErrorMessage("Unable to send mail");
+ return false;
+ }
+ return false;
+ }
+}
+
+// Make our class available automatically
+$mail = new Mail ();
+$mail->setDebug($debug);
+$mail->setMysql($mysqli);
+$mail->setSmarty($smarty);
+$mail->setConfig($config);
+
+?>
diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php
new file mode 100644
index 00000000..a9eca1af
--- /dev/null
+++ b/public/include/classes/notification.class.php
@@ -0,0 +1,45 @@
+mysqli->prepare("SELECT id FROM $this->table WHERE data = ? LIMIT 1");
+ if ($stmt && $stmt->bind_param('s', $data) && $stmt->execute() && $stmt->store_result() && $stmt->num_rows == 1)
+ return true;
+ // Catchall
+ // Does not seem to have a notification set
+ return false;
+ }
+
+ /**
+ * Add a new notification to the table
+ * @param type string Type of the notification
+ * @return bool
+ **/
+ public function addNotification($type, $data) {
+ // Store notification data as json
+ $data = json_encode($data);
+ $stmt = $this->mysqli->prepare("INSERT INTO $this->table (type, data) VALUES (?,?)");
+ if ($stmt && $stmt->bind_param('ss', $type, $data) && $stmt->execute())
+ return true;
+ $this->debug->append("Failed to add notification for $type with $data: " . $this->mysqli->error);
+ $this->setErrorMessage("Unable to add new notification");
+ return false;
+ }
+}
+
+$notification = new Notification();
+$notification->setDebug($debug);
+$notification->setMysql($mysqli);
+$notification->setSmarty($smarty);
+$notification->setConfig($config);
diff --git a/public/include/classes/worker.class.php b/public/include/classes/worker.class.php
index 6052eaac..a5052ba9 100644
--- a/public/include/classes/worker.class.php
+++ b/public/include/classes/worker.class.php
@@ -58,6 +58,26 @@ class Worker {
return false;
}
+ /**
+ * Fetch all IDLE workers that have monitoring enabled
+ * @param none
+ * @return data array Workers in IDLE state and monitoring enabled
+ **/
+ public function getAllIdleWorkers() {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("
+ SELECT account_id, id, username
+ FROM " . $this->table . "
+ WHERE monitor = 1 AND ( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) = 0");
+
+ if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_all(MYSQLI_ASSOC);
+ // Catchall
+ $this->setErrorMessage("Unable to fetch IDLE, monitored workers");
+ echo $this->mysqli->error;
+ return false;
+ }
+
/**
* Fetch all workers for an account
* @param account_id int User ID
diff --git a/public/templates/mail/idle_worker.tpl b/public/templates/mail/idle_worker.tpl
new file mode 100644
index 00000000..a21aaac3
--- /dev/null
+++ b/public/templates/mail/idle_worker.tpl
@@ -0,0 +1,9 @@
+
+
+One of your workers is currently IDLE.
+Since monitoring is enabled for this worker, this notification was sent.
+Please check your workers!
+
+
+
+
diff --git a/sql/mmcfe_ng_structure.sql b/sql/mmcfe_ng_structure.sql
index c3c626bd..a971d455 100644
--- a/sql/mmcfe_ng_structure.sql
+++ b/sql/mmcfe_ng_structure.sql
@@ -3,7 +3,7 @@
-- http://www.phpmyadmin.net
--
-- Host: localhost
--- Generation Time: Jun 06, 2013 at 09:01 PM
+-- Generation Time: Jun 07, 2013 at 02:42 PM
-- Server version: 5.5.31-0ubuntu0.13.04.1
-- PHP Version: 5.4.9-4ubuntu2
@@ -69,6 +69,20 @@ CREATE TABLE IF NOT EXISTS `blocks` (
-- --------------------------------------------------------
+--
+-- Table structure for table `notifications`
+--
+
+CREATE TABLE IF NOT EXISTS `notifications` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `type` varchar(25) NOT NULL,
+ `data` text NOT NULL,
+ `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
--
-- Table structure for table `pool_worker`
--
@@ -136,7 +150,7 @@ CREATE TABLE IF NOT EXISTS `shares_archive` (
PRIMARY KEY (`id`),
UNIQUE KEY `share_id` (`share_id`),
KEY `time` (`time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
-- --------------------------------------------------------
@@ -153,7 +167,7 @@ CREATE TABLE IF NOT EXISTS `statistics_shares` (
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`),
KEY `block_id` (`block_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
From 69a3761be58e81868c2bb511b88e7f9c20af719d Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 15:07:26 +0200
Subject: [PATCH 056/168] Adding notification reset once worker is active
Go through all active notifications (active means they are not notified
again) and check if their state has changed. If so, mark as inactive and
allow for re-notification of the same type and data.
---
cronjobs/notifications.php | 34 +++++++++++------
public/include/classes/mail.class.php | 2 +-
public/include/classes/notification.class.php | 38 ++++++++++++++++++-
public/include/classes/worker.class.php | 21 ++++++++++
4 files changed, 80 insertions(+), 15 deletions(-)
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
index 7bca08ec..e70d2b07 100755
--- a/cronjobs/notifications.php
+++ b/cronjobs/notifications.php
@@ -22,21 +22,31 @@ limitations under the License.
// Include all settings and classes
require_once('shared.inc.php');
+// Find all IDLE workers
$aWorkers = $worker->getAllIdleWorkers();
if (empty($aWorkers)) {
verbose("No idle workers found\n");
- exit;
-}
-
-foreach ($aWorkers as $aWorker) {
- $aData = $aWorker;
- $aData['username'] = $user->getUserName($aWorker['account_id']);
- $aData['email'] = $user->getUserEmail($aData['username']);
- if (!$notification->isNotified($aData)) {
- if (!$notification->addNotification('idle_worker', $aData) && $notification->sendMail('sebastian@grewe.ca', 'idle_worker', $aData))
- verbose("Unable to send notification: " . $notification->getError() . "\n");
- } else {
- verbose("Already notified for this worker\n");
+} else {
+ foreach ($aWorkers as $aWorker) {
+ $aData = $aWorker;
+ $aData['username'] = $user->getUserName($aWorker['account_id']);
+ $aData['email'] = $user->getUserEmail($aData['username']);
+ if (!$notification->isNotified($aData)) {
+ if (!$notification->addNotification('idle_worker', $aData) && $notification->sendMail('sebastian@grewe.ca', 'idle_worker', $aData))
+ verbose("Unable to send notification: " . $notification->getError() . "\n");
+ } else {
+ verbose("Already notified for this worker\n");
+ }
}
}
+// We notified, lets check which recovered
+$aNotifications = $notification->getAllActive();
+foreach ($aNotifications as $aNotification) {
+ $aData = json_decode($aNotification['data'], true);
+ $aWorker = $worker->getWorker($aData['id']);
+ if ($aWorker['active'] == 1)
+ if (!$notification->setInactive($aNotification['id']))
+ verbose("Failed to set notification inactive for " . $aWorker['username'] . "\n");
+}
+
?>
diff --git a/public/include/classes/mail.class.php b/public/include/classes/mail.class.php
index 6c7cc0f1..a1cf2137 100644
--- a/public/include/classes/mail.class.php
+++ b/public/include/classes/mail.class.php
@@ -20,7 +20,7 @@ class Mail {
$this->config = $config;
}
- private function checkStmt($bState) {
+ function checkStmt($bState) {
$this->debug->append("STA " . __METHOD__, 4);
if ($bState ===! true) {
$this->debug->append("Failed to prepare statement: " . $this->mysqli->error);
diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php
index a9eca1af..9a6dcf3b 100644
--- a/public/include/classes/notification.class.php
+++ b/public/include/classes/notification.class.php
@@ -7,13 +7,36 @@ if (!defined('SECURITY'))
class Notification extends Mail {
var $table = 'notifications';
+ public function setInactive($id) {
+ $field = array(
+ 'name' => 'active',
+ 'type' => 'i',
+ 'value' => 0
+ );
+ return $this->updateSingle($id, $field);
+ }
+
+ /**
+ * Update a single row in a table
+ * @param userID int Account ID
+ * @param field string Field to update
+ * @return bool
+ **/
+ private function updateSingle($id, $field) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("UPDATE $this->table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1");
+ if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute())
+ return true;
+ $this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id");
+ return false;
+ }
/**
* We check our notification table for existing data
* so we can avoid duplicate entries
**/
public function isNotified($aData) {
$data = json_encode($aData);
- $stmt = $this->mysqli->prepare("SELECT id FROM $this->table WHERE data = ? LIMIT 1");
+ $stmt = $this->mysqli->prepare("SELECT id FROM $this->table WHERE data = ? AND active = 1 LIMIT 1");
if ($stmt && $stmt->bind_param('s', $data) && $stmt->execute() && $stmt->store_result() && $stmt->num_rows == 1)
return true;
// Catchall
@@ -21,6 +44,17 @@ class Notification extends Mail {
return false;
}
+ /**
+ * Get all active notifications
+ **/
+ public function getAllActive() {
+ $stmt =$this->mysqli->prepare("SELECT id, data FROM $this->table WHERE active = 1 LIMIT 1");
+ if ($stmt && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_all(MYSQLI_ASSOC);
+ // Catchall
+ return false;
+ }
+
/**
* Add a new notification to the table
* @param type string Type of the notification
@@ -29,7 +63,7 @@ class Notification extends Mail {
public function addNotification($type, $data) {
// Store notification data as json
$data = json_encode($data);
- $stmt = $this->mysqli->prepare("INSERT INTO $this->table (type, data) VALUES (?,?)");
+ $stmt = $this->mysqli->prepare("INSERT INTO $this->table (type, data, active) VALUES (?,?,1)");
if ($stmt && $stmt->bind_param('ss', $type, $data) && $stmt->execute())
return true;
$this->debug->append("Failed to add notification for $type with $data: " . $this->mysqli->error);
diff --git a/public/include/classes/worker.class.php b/public/include/classes/worker.class.php
index a5052ba9..6a9f6524 100644
--- a/public/include/classes/worker.class.php
+++ b/public/include/classes/worker.class.php
@@ -78,6 +78,27 @@ class Worker {
return false;
}
+ /**
+ * Fetch a specific worker and its status
+ * @param id int Worker ID
+ * @return mixed array Worker details
+ **/
+ public function getWorker($id) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("
+ SELECT id, username, password, monitor,
+ ( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS active,
+ ( SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS hashrate
+ FROM $this->table
+ WHERE id = ?
+ ");
+ if ($this->checkStmt($stmt) && $stmt->bind_param('i', $id) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_assoc();
+ // Catchall
+ echo $this->mysqli->error;
+ return false;
+ }
+
/**
* Fetch all workers for an account
* @param account_id int User ID
From 4da9fd2369088d9ed3852b8f3465b7582895a1c4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 15:35:58 +0200
Subject: [PATCH 057/168] Working notification system
* Added things to mail templates
* Modified user password reset call for new mail template
* Added BASEPATH to smarty code to ensure templates are compiled in the
proper directory
* Updated mail and notification class
* Updated notification cron
* Added notification cron to run-cron list
---
cronjobs/notifications.php | 23 +++++++++++++------
cronjobs/run-crons.sh | 2 +-
public/include/classes/mail.class.php | 11 +++++++--
public/include/classes/notification.class.php | 1 +
public/include/classes/user.class.php | 1 +
public/include/smarty.inc.php | 6 ++---
public/templates/mail/idle_worker.tpl | 2 +-
public/templates/mail/subject.tpl | 2 +-
8 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
index e70d2b07..45bda82a 100755
--- a/cronjobs/notifications.php
+++ b/cronjobs/notifications.php
@@ -30,23 +30,32 @@ if (empty($aWorkers)) {
foreach ($aWorkers as $aWorker) {
$aData = $aWorker;
$aData['username'] = $user->getUserName($aWorker['account_id']);
+ $aData['subject'] = 'IDLE Worker : ' . $aWorker['username'];
$aData['email'] = $user->getUserEmail($aData['username']);
- if (!$notification->isNotified($aData)) {
- if (!$notification->addNotification('idle_worker', $aData) && $notification->sendMail('sebastian@grewe.ca', 'idle_worker', $aData))
- verbose("Unable to send notification: " . $notification->getError() . "\n");
- } else {
- verbose("Already notified for this worker\n");
+ if ( $notification->isNotified($aData) ) {
+ verbose("Worker already notified\n");
+ continue;
}
+ if ($notification->addNotification('idle_worker', $aData) && $notification->sendMail($aData['email'], 'idle_worker', $aData)) {
+ verbose ("Notified " . $aData['email'] . " for IDLE worker " . $aWorker['username'] . "\n");
+ } else {
+ verbose("Unable to send notification: " . $notification->getError() . "\n");
+ }
}
}
+
// We notified, lets check which recovered
$aNotifications = $notification->getAllActive();
foreach ($aNotifications as $aNotification) {
$aData = json_decode($aNotification['data'], true);
$aWorker = $worker->getWorker($aData['id']);
- if ($aWorker['active'] == 1)
- if (!$notification->setInactive($aNotification['id']))
+ if ($aWorker['active'] == 1) {
+ if ($notification->setInactive($aNotification['id'])) {
+ verbose("Marked notification " . $aNotification['id'] . " as inactive\n");
+ } else {
verbose("Failed to set notification inactive for " . $aWorker['username'] . "\n");
+ }
+ }
}
?>
diff --git a/cronjobs/run-crons.sh b/cronjobs/run-crons.sh
index 730a9063..5f9179dc 100755
--- a/cronjobs/run-crons.sh
+++ b/cronjobs/run-crons.sh
@@ -16,7 +16,7 @@ PIDFILE='/tmp/mmcfe-ng-cron.pid'
CRONHOME='.'
# List of cruns to execute
-CRONS="findblock.php proportional_payout.php blockupdate.php auto_payout.php tickerupdate.php"
+CRONS="findblock.php proportional_payout.php blockupdate.php auto_payout.php tickerupdate.php notifications.php"
# Additional arguments to pass to cronjobs
CRONARGS="-v"
diff --git a/public/include/classes/mail.class.php b/public/include/classes/mail.class.php
index a1cf2137..2800500c 100644
--- a/public/include/classes/mail.class.php
+++ b/public/include/classes/mail.class.php
@@ -19,7 +19,12 @@ class Mail {
public function setConfig($config) {
$this->config = $config;
}
-
+ public function setErrorMessage($msg) {
+ $this->sError = $msg;
+ }
+ public function getError() {
+ return $this->sError;
+ }
function checkStmt($bState) {
$this->debug->append("STA " . __METHOD__, 4);
if ($bState ===! true) {
@@ -30,8 +35,10 @@ class Mail {
return true;
}
- public function sendMail($email, $template, $vars) {
+ public function sendMail($email, $template, $aData) {
$this->smarty->assign('WEBSITENAME', $this->config['website']['name']);
+ $this->smarty->assign('SUBJECT', $aData['subject']);
+ $this->smarty->assign('DATA', $aData);
$headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php
index 9a6dcf3b..983db437 100644
--- a/public/include/classes/notification.class.php
+++ b/public/include/classes/notification.class.php
@@ -41,6 +41,7 @@ class Notification extends Mail {
return true;
// Catchall
// Does not seem to have a notification set
+ $this->setErrorMessage("Unable to run query: " . $this->mysqli->error);
return false;
}
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 8db17a1e..b4627729 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -486,6 +486,7 @@ class User {
}
$smarty->assign('TOKEN', $token);
$smarty->assign('USERNAME', $username);
+ $smarty->assign('SUBJECT', 'Password Reset Request');
$smarty->assign('WEBSITENAME', $this->config['website']['name']);
$headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
$headers .= "MIME-Version: 1.0\n";
diff --git a/public/include/smarty.inc.php b/public/include/smarty.inc.php
index b2e67f37..5668e1d3 100644
--- a/public/include/smarty.inc.php
+++ b/public/include/smarty.inc.php
@@ -16,10 +16,10 @@ $smarty = new Smarty;
// Assign our local paths
$debug->append('Define Smarty Paths', 3);
-$smarty->template_dir = 'templates/' . THEME . '/';
-$smarty->compile_dir = 'templates/compile/';
+$smarty->template_dir = BASEPATH . 'templates/' . THEME . '/';
+$smarty->compile_dir = BASEPATH . 'templates/compile/';
// Optional smarty caching, check Smarty documentation for details
$smarty->caching = $config['cache'];
-$smarty->cache_dir = "templates/cache";
+$smarty->cache_dir = BASEPATH . "templates/cache";
?>
diff --git a/public/templates/mail/idle_worker.tpl b/public/templates/mail/idle_worker.tpl
index a21aaac3..6d1c282c 100644
--- a/public/templates/mail/idle_worker.tpl
+++ b/public/templates/mail/idle_worker.tpl
@@ -1,6 +1,6 @@
-One of your workers is currently IDLE.
+One of your workers is currently IDLE: {$DATA.username}
Since monitoring is enabled for this worker, this notification was sent.
Please check your workers!
diff --git a/public/templates/mail/subject.tpl b/public/templates/mail/subject.tpl
index 665e26f5..94fd6a28 100644
--- a/public/templates/mail/subject.tpl
+++ b/public/templates/mail/subject.tpl
@@ -1 +1 @@
-[ {$WEBSITENAME} ] Password Reset Request
+[ {$WEBSITENAME} ] {$SUBJECT}
From d5d0b5470542514664dd8c1ca61ccbdd35253c58 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 15:39:43 +0200
Subject: [PATCH 058/168] adding new structure for notifications
---
sql/mmcfe_ng_structure.sql | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/sql/mmcfe_ng_structure.sql b/sql/mmcfe_ng_structure.sql
index a971d455..039b9a04 100644
--- a/sql/mmcfe_ng_structure.sql
+++ b/sql/mmcfe_ng_structure.sql
@@ -3,7 +3,7 @@
-- http://www.phpmyadmin.net
--
-- Host: localhost
--- Generation Time: Jun 07, 2013 at 02:42 PM
+-- Generation Time: Jun 07, 2013 at 03:39 PM
-- Server version: 5.5.31-0ubuntu0.13.04.1
-- PHP Version: 5.4.9-4ubuntu2
@@ -65,7 +65,7 @@ CREATE TABLE IF NOT EXISTS `blocks` (
PRIMARY KEY (`id`),
UNIQUE KEY `height` (`height`,`blockhash`),
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';
-- --------------------------------------------------------
@@ -76,10 +76,13 @@ CREATE TABLE IF NOT EXISTS `blocks` (
CREATE TABLE IF NOT EXISTS `notifications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(25) NOT NULL,
- `data` text NOT NULL,
+ `data` varchar(255) NOT NULL,
+ `active` tinyint(1) NOT NULL DEFAULT '1',
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+ PRIMARY KEY (`id`),
+ KEY `active` (`active`),
+ KEY `data` (`data`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -150,7 +153,7 @@ CREATE TABLE IF NOT EXISTS `shares_archive` (
PRIMARY KEY (`id`),
UNIQUE KEY `share_id` (`share_id`),
KEY `time` (`time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
-- --------------------------------------------------------
@@ -167,7 +170,7 @@ CREATE TABLE IF NOT EXISTS `statistics_shares` (
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`),
KEY `block_id` (`block_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -187,7 +190,7 @@ CREATE TABLE IF NOT EXISTS `transactions` (
KEY `block_id` (`block_id`),
KEY `account_id` (`account_id`),
KEY `type` (`type`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
From 531e28cee85f9b96136cfe128f8cfaf4860ee68b Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 21:37:14 +0200
Subject: [PATCH 059/168] Adding support for PPS payout method
This commit changed a few things in the backend and classes code:
* Any _PPS transaction does NOT need to be confirmed
* Queries updated for added _PPS transactions
* Template updated to properly display these transactions
Cronjob
* Added pps_payput cron to run payouts based on worker submitted shares
* **IMPORTANT**: Can NOT be run with proportional_payout!
Addresses #70
---
cronjobs/pps_payout.php | 87 +++++++++++++++++++
public/include/classes/share.class.php | 15 ++++
public/include/classes/transaction.class.php | 18 ++--
.../mmcFE/account/transactions/default.tpl | 5 +-
4 files changed, 118 insertions(+), 7 deletions(-)
create mode 100755 cronjobs/pps_payout.php
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
new file mode 100755
index 00000000..a71c42a3
--- /dev/null
+++ b/cronjobs/pps_payout.php
@@ -0,0 +1,87 @@
+#!/usr/bin/php
+can_connect() === true ){
+ $dDifficulty = $bitcoin->getdifficulty();
+} else {
+ verbose("Aborted: " . $bitcoin->can_connect() . "\n");
+ exit(1);
+}
+
+// Value per share calculation
+$pps_value = 50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']);
+
+// Find our last share accounted and last inserted share for PPS calculations
+$iPreviousShareId = $setting->getValue('pps_last_share_id');
+$iLastShareId = $share->getLastInsertedShareId();
+
+// Check for all new shares, we start one higher as our last accounted share to avoid duplicates
+$aAccountShares = $share->getSharesForAccounts($iPreviousShareId + 1, $iLastShareId);
+
+verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\t\tStatus\n");
+
+foreach ($aAccountShares as $aData) {
+ // Take our valid shares and multiply by per share value
+ $aData['payout'] = $aData['valid'] * $pps_value;
+
+ // Defaults
+ $aData['fee' ] = 0;
+ $aData['donation'] = 0;
+
+ // Calculate block fees
+ if ($config['fees'] > 0)
+ $aData['fee'] = number_format(round($config['fees'] / 100 * $aData['payout'], 8), 8);
+ // Calculate donation amount
+ $aData['donation'] = number_format(round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8), 8);
+
+ verbose($aData['id'] . "\t" .
+ $aData['username'] . "\t" .
+ $aData['invalid'] . "\t" .
+ $aData['valid'] . "\t*\t" .
+ $pps_value . "\t=\t" .
+ $aData['payout'] . "\t" .
+ $aData['donation'] . "\t" .
+ $aData['fee'] . "\t");
+
+ $strStatus = "OK";
+ // Add new credit transaction
+ if (!$transaction->addTransaction($aData['id'], $aData['payout'], 'Credit_PPS'))
+ $strStatus = "Transaction Failed";
+ // Add new fee debit for this block
+ if ($aData['fee'] > 0 && $config['fees'] > 0)
+ if (!$transaction->addTransaction($aData['id'], $aData['fee'], 'Fee_PPS'))
+ $strStatus = "Fee Failed";
+ // Add new donation debit
+ if ($aData['donation'] > 0)
+ if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation_PPS'))
+ $strStatus = "Donation Failed";
+ verbose($strStatus . "\n");
+}
+
+// Store our last inserted ID for the next run
+$setting->setValue('pps_last_share_id', $iLastShareId);
+
+verbose("\n\n------------------------------------------------------------------------------------\n\n");
+?>
diff --git a/public/include/classes/share.class.php b/public/include/classes/share.class.php
index b0a3b249..1033f92c 100644
--- a/public/include/classes/share.class.php
+++ b/public/include/classes/share.class.php
@@ -44,6 +44,21 @@ class Share {
return $this->table;
}
+ /**
+ * Get last inserted Share ID from Database
+ * Used for PPS calculations without moving to archive
+ **/
+ public function getLastInsertedShareId() {
+ $stmt = $this->mysqli->prepare("
+ SELECT MAX(id) AS id FROM $this->table
+ ");
+ if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_object()->id;
+ // Catchall
+ $this->setErrorMessage('Failed to fetch last inserted share ID');
+ return false;
+ }
+
/**
* Get all valid shares for this round
* @param previous_upstream int Previous found share accepted by upstream to limit results
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index 020140d3..711e893f 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -142,7 +142,7 @@ class Transaction {
(
SELECT sum(t.amount) AS credit
FROM $this->table AS t
- WHERE t.type = 'Credit'
+ WHERE t.type IN ('Credit', 'Credit_PPS')
) AS t1,
(
SELECT sum(t.amount) AS debit
@@ -152,7 +152,7 @@ class Transaction {
(
SELECT sum(t.amount) AS other
FROM " . $this->table . " AS t
- WHERE t.type IN ('Donation','Fee')
+ WHERE t.type IN ('Donation','Fee','Donation_PPS','Fee_PPS')
) AS t3");
if ($this->checkStmt($stmt) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
return $dBalance;
@@ -176,8 +176,11 @@ class Transaction {
SELECT sum(t.amount) AS credit
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type = 'Credit'
- AND b.confirmations >= ?
+ WHERE
+ (
+ ( t.type = 'Credit' AND b.confirmations >= ? ) OR
+ ( t.type = 'Credit_PPS' )
+ )
AND t.account_id = ?
) AS t1,
(
@@ -190,8 +193,11 @@ class Transaction {
SELECT sum(t.amount) AS other
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type IN ('Donation','Fee')
- AND b.confirmations >= ?
+ WHERE
+ (
+ ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
+ ( t.type IN ('Donation_PPS', 'Fee_PPS') )
+ )
AND t.account_id = ?
) AS t3
");
diff --git a/public/templates/mmcFE/account/transactions/default.tpl b/public/templates/mmcFE/account/transactions/default.tpl
index 8f5282e1..dd31723f 100644
--- a/public/templates/mmcFE/account/transactions/default.tpl
+++ b/public/templates/mmcFE/account/transactions/default.tpl
@@ -18,6 +18,9 @@
($TRANSACTIONS[transaction].type == 'Credit' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Donation' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Fee' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
+ or $TRANSACTIONS[transaction].type == 'Credit_PPS'
+ or $TRANSACTIONS[transaction].type == 'Fee_PPS'
+ or $TRANSACTIONS[transaction].type == 'Donation_PPS'
or $TRANSACTIONS[transaction].type == 'Debit_AP'
or $TRANSACTIONS[transaction].type == 'Debit_MP'
)}
@@ -27,7 +30,7 @@
{$TRANSACTIONS[transaction].type}
{$TRANSACTIONS[transaction].coin_address}
{if $TRANSACTIONS[transaction].height == 0}n/a{else}{$TRANSACTIONS[transaction].height}{/if}
- {$TRANSACTIONS[transaction].amount}
+ {$TRANSACTIONS[transaction].amount}
{/if}
{/section}
From dcfbd83270292261e2a0c57964055a6feb57faa8 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:31:35 +0200
Subject: [PATCH 060/168] properly format payout and round it
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index a71c42a3..1dafa288 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -44,7 +44,7 @@ verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
- $aData['payout'] = $aData['valid'] * $pps_value;
+ $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8));
// Defaults
$aData['fee' ] = 0;
From 5f1e52767e88db2dd8dff843b8463b8b2a9b8ca5 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:34:02 +0200
Subject: [PATCH 061/168] forgot 8 decimals
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index 1dafa288..bef78f2a 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -44,7 +44,7 @@ verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
- $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8));
+ $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8), 8);
// Defaults
$aData['fee' ] = 0;
From 4a36479fe22205d959e80e17e314da294aa5adbe Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:45:53 +0200
Subject: [PATCH 062/168] properly format pps value to 12 digits
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index bef78f2a..e2804595 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -31,7 +31,7 @@ if ( $bitcoin->can_connect() === true ){
}
// Value per share calculation
-$pps_value = 50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']);
+$pps_value = number_format(round(50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']), 12) ,12);
// Find our last share accounted and last inserted share for PPS calculations
$iPreviousShareId = $setting->getValue('pps_last_share_id');
From b6da195da5954e790d5deb521d2a090094a2c2ef Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:48:09 +0200
Subject: [PATCH 063/168] moved table header to the left
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index e2804595..427035d5 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -40,7 +40,7 @@ $iLastShareId = $share->getLastInsertedShareId();
// Check for all new shares, we start one higher as our last accounted share to avoid duplicates
$aAccountShares = $share->getSharesForAccounts($iPreviousShareId + 1, $iLastShareId);
-verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\t\tStatus\n");
+verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\tPayout\t\tDonation\tFee\t\tStatus\n");
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
From efdbff8e5329b456b9d0a7481d5533fd6178d8c4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 20:07:55 +0200
Subject: [PATCH 064/168] Do not include unconfirmed transactions in balance
view
This will fix #139 showing wrong liquid asset counts. Since
that was confusing I ensured confirmations are included in the calculations.
---
public/include/classes/transaction.class.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index 020140d3..e4ff684e 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -142,7 +142,9 @@ class Transaction {
(
SELECT sum(t.amount) AS credit
FROM $this->table AS t
+ LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type = 'Credit'
+ AND b.confirmations >= " . $this->config['confirmations'] . "
) AS t1,
(
SELECT sum(t.amount) AS debit
@@ -152,7 +154,9 @@ class Transaction {
(
SELECT sum(t.amount) AS other
FROM " . $this->table . " AS t
+ LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type IN ('Donation','Fee')
+ AND b.confirmations >= " . $this->config['confirmations'] . "
) AS t3");
if ($this->checkStmt($stmt) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
return $dBalance;
From 02eb400de9dbbeac1860a95d40e3e645448ce074 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 20:09:54 +0200
Subject: [PATCH 065/168] proper whitespacing
---
public/include/classes/transaction.class.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index e4ff684e..a487e5ec 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -142,9 +142,9 @@ class Transaction {
(
SELECT sum(t.amount) AS credit
FROM $this->table AS t
- LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
+ LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type = 'Credit'
- AND b.confirmations >= " . $this->config['confirmations'] . "
+ AND b.confirmations >= " . $this->config['confirmations'] . "
) AS t1,
(
SELECT sum(t.amount) AS debit
@@ -154,9 +154,9 @@ class Transaction {
(
SELECT sum(t.amount) AS other
FROM " . $this->table . " AS t
- LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
+ LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type IN ('Donation','Fee')
- AND b.confirmations >= " . $this->config['confirmations'] . "
+ AND b.confirmations >= " . $this->config['confirmations'] . "
) AS t3");
if ($this->checkStmt($stmt) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
return $dBalance;
From 9eeb088734b112684295d22fc0961adc03ef3db5 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 7 Jun 2013 20:15:23 +0200
Subject: [PATCH 066/168] check if notifications exist at all
---
cronjobs/notifications.php | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
index 45bda82a..aa2bf8a9 100755
--- a/cronjobs/notifications.php
+++ b/cronjobs/notifications.php
@@ -46,16 +46,17 @@ if (empty($aWorkers)) {
// We notified, lets check which recovered
$aNotifications = $notification->getAllActive();
-foreach ($aNotifications as $aNotification) {
- $aData = json_decode($aNotification['data'], true);
- $aWorker = $worker->getWorker($aData['id']);
- if ($aWorker['active'] == 1) {
- if ($notification->setInactive($aNotification['id'])) {
- verbose("Marked notification " . $aNotification['id'] . " as inactive\n");
- } else {
- verbose("Failed to set notification inactive for " . $aWorker['username'] . "\n");
+if (!empty($aNotifications)) {
+ foreach ($aNotifications as $aNotification) {
+ $aData = json_decode($aNotification['data'], true);
+ $aWorker = $worker->getWorker($aData['id']);
+ if ($aWorker['active'] == 1) {
+ if ($notification->setInactive($aNotification['id'])) {
+ verbose("Marked notification " . $aNotification['id'] . " as inactive\n");
+ } else {
+ verbose("Failed to set notification inactive for " . $aWorker['username'] . "\n");
+ }
}
}
}
-
?>
From 88ade9cfa3028a9335a58b2f12b35cb0bb20448f Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 13:10:58 +0200
Subject: [PATCH 067/168] Adding support for various notifications
* Adding new SQL upgrade for notifications
* Added support for per user notification settings
* Added account_id to notifications table
* Added new notification_settings table
* Added new account page: notifications
Addresses #144
---
cronjobs/notifications.php | 2 +-
public/include/classes/notification.class.php | 83 +++++++++++++++++--
.../pages/account/notifications.inc.php | 25 ++++++
.../mmcFE/account/notifications/default.tpl | 60 ++++++++++++++
public/templates/mmcFE/global/navigation.tpl | 1 +
sql/issue_144_notification_upgrade.sql | 6 ++
6 files changed, 171 insertions(+), 6 deletions(-)
create mode 100644 public/include/pages/account/notifications.inc.php
create mode 100644 public/templates/mmcFE/account/notifications/default.tpl
create mode 100644 sql/issue_144_notification_upgrade.sql
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
index aa2bf8a9..eddef3de 100755
--- a/cronjobs/notifications.php
+++ b/cronjobs/notifications.php
@@ -36,7 +36,7 @@ if (empty($aWorkers)) {
verbose("Worker already notified\n");
continue;
}
- if ($notification->addNotification('idle_worker', $aData) && $notification->sendMail($aData['email'], 'idle_worker', $aData)) {
+ if ($notification->addNotification($aWorker['account_id'], 'idle_worker', $aData) && $notification->sendMail($aData['email'], 'idle_worker', $aData)) {
verbose ("Notified " . $aData['email'] . " for IDLE worker " . $aWorker['username'] . "\n");
} else {
verbose("Unable to send notification: " . $notification->getError() . "\n");
diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php
index 983db437..cff05abb 100644
--- a/public/include/classes/notification.class.php
+++ b/public/include/classes/notification.class.php
@@ -6,6 +6,7 @@ if (!defined('SECURITY'))
class Notification extends Mail {
var $table = 'notifications';
+ var $tableSettings = 'notification_settings';
public function setInactive($id) {
$field = array(
@@ -22,9 +23,10 @@ class Notification extends Mail {
* @param field string Field to update
* @return bool
**/
- private function updateSingle($id, $field) {
+ private function updateSingle($id, $field, $table='') {
+ if (empty($table)) $table = $this->table;
$this->debug->append("STA " . __METHOD__, 4);
- $stmt = $this->mysqli->prepare("UPDATE $this->table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1");
+ $stmt = $this->mysqli->prepare("UPDATE $table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute())
return true;
$this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id");
@@ -35,6 +37,7 @@ class Notification extends Mail {
* so we can avoid duplicate entries
**/
public function isNotified($aData) {
+ $this->debug->append("STA " . __METHOD__, 4);
$data = json_encode($aData);
$stmt = $this->mysqli->prepare("SELECT id FROM $this->table WHERE data = ? AND active = 1 LIMIT 1");
if ($stmt && $stmt->bind_param('s', $data) && $stmt->execute() && $stmt->store_result() && $stmt->num_rows == 1)
@@ -49,6 +52,7 @@ class Notification extends Mail {
* Get all active notifications
**/
public function getAllActive() {
+ $this->debug->append("STA " . __METHOD__, 4);
$stmt =$this->mysqli->prepare("SELECT id, data FROM $this->table WHERE active = 1 LIMIT 1");
if ($stmt && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_all(MYSQLI_ASSOC);
@@ -61,16 +65,85 @@ class Notification extends Mail {
* @param type string Type of the notification
* @return bool
**/
- public function addNotification($type, $data) {
+ public function addNotification($account_id, $type, $data) {
+ $this->debug->append("STA " . __METHOD__, 4);
// Store notification data as json
$data = json_encode($data);
- $stmt = $this->mysqli->prepare("INSERT INTO $this->table (type, data, active) VALUES (?,?,1)");
- if ($stmt && $stmt->bind_param('ss', $type, $data) && $stmt->execute())
+ $stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, type, data, active) VALUES (?, ?,?,1)");
+ if ($stmt && $stmt->bind_param('iss', $account_id, $type, $data) && $stmt->execute())
return true;
$this->debug->append("Failed to add notification for $type with $data: " . $this->mysqli->error);
$this->setErrorMessage("Unable to add new notification");
return false;
}
+
+ /**
+ * Fetch notifications for a user account
+ * @param id int Account ID
+ * @return array Notification data
+ **/
+ public function getNofifications($account_id) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE account_id = ? ORDER BY time DESC");
+ if ($stmt && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_all(MYSQLI_ASSOC);
+ // Catchall
+ return false;
+ }
+
+ /**
+ * Fetch notification settings for user account
+ * @param id int Account ID
+ * @return array Notification settings
+ **/
+ public function getNotificationSettings($account_id) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("SELECT * FROM $this->tableSettings WHERE account_id = ?");
+ if ($stmt && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) {
+ while ($row = $result->fetch_assoc()) {
+ $aData[$row['type']] = $row['active'];
+ }
+ return $aData;
+ }
+ // Catchall
+ return false;
+ }
+
+ /**
+ * Update accounts notification settings
+ * @param account_id int Account ID
+ * @param data array Data array
+ * @return bool
+ **/
+ public function updateSettings($account_id, $data) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $failed = $ok = 0;
+ foreach ($data as $type => $active) {
+ // Does an entry exist already
+ $stmt = $this->mysqli->prepare("SELECT * FROM $this->tableSettings WHERE account_id = ? AND type = ?");
+ if ($stmt && $stmt->bind_param('is', $account_id, $type) && $stmt->execute() && $stmt->store_result() && $stmt->num_rows() > 0) {
+ // We found a matching row
+ $stmt = $this->mysqli->prepare("UPDATE $this->tableSettings SET active = ? WHERE type = ? AND account_id = ?");
+ if ($stmt && $stmt->bind_param('isi', $active, $type, $account_id) && $stmt->execute() && $stmt->close()) {
+ $ok++;
+ } else {
+ $failed++;
+ }
+ } else {
+ $stmt = $this->mysqli->prepare("INSERT INTO $this->tableSettings (active, type, account_id) VALUES (?,?,?)");
+ if ($stmt && $stmt->bind_param('isi', $active, $type, $account_id) && $stmt->execute()) {
+ $ok++;
+ } else {
+ $failed++;
+ }
+ }
+ }
+ if ($failed > 0) {
+ $this->setErrorMessage('Failed to update ' . $failed . ' settings');
+ return false;
+ }
+ return true;
+ }
}
$notification = new Notification();
diff --git a/public/include/pages/account/notifications.inc.php b/public/include/pages/account/notifications.inc.php
new file mode 100644
index 00000000..2ab9c0d0
--- /dev/null
+++ b/public/include/pages/account/notifications.inc.php
@@ -0,0 +1,25 @@
+updateSettings($_SESSION['USERDATA']['id'], $_REQUEST['data'])) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Updated notification settings');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update settings', 'TYPE' => 'errormsg');
+ }
+}
+
+// Fetch notifications
+$aNotifications = $notification->getNofifications($_SESSION['USERDATA']['id']);
+if (!$aNotifications) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any notifications', 'TYPE' => 'errormsg');
+
+// Fetch user notification settings
+$aSettings = $notification->getNotificationSettings($_SESSION['USERDATA']['id']);
+
+$smarty->assign('NOTIFICATIONS', $aNotifications);
+$smarty->assign('SETTINGS', $aSettings);
+$smarty->assign('CONTENT', 'default.tpl');
+?>
diff --git a/public/templates/mmcFE/account/notifications/default.tpl b/public/templates/mmcFE/account/notifications/default.tpl
new file mode 100644
index 00000000..1b737f79
--- /dev/null
+++ b/public/templates/mmcFE/account/notifications/default.tpl
@@ -0,0 +1,60 @@
+{include file="global/block_header.tpl" ALIGN="left" BLOCK_HEADER="Notification Settings"}
+
+
+
+
+
+
+{include file="global/block_footer.tpl"}
+
+{include file="global/block_header.tpl" ALIGN="right" BLOCK_HEADER="Notification History"}
+
+ {include file="global/pagination.tpl"}
+
+
+
+ ID
+ Time
+ Type
+ Active
+
+
+
+{section notification $NOTIFICATIONS}
+
+ {$NOTIFICATIONS[notification].id}
+ {$NOTIFICATIONS[notification].time}
+ {$NOTIFICATIONS[notification].type}
+
+
+
+
+{/section}
+
+
+
+{include file="global/block_footer.tpl"}
diff --git a/public/templates/mmcFE/global/navigation.tpl b/public/templates/mmcFE/global/navigation.tpl
index 6a0cdb37..3f26387a 100644
--- a/public/templates/mmcFE/global/navigation.tpl
+++ b/public/templates/mmcFE/global/navigation.tpl
@@ -7,6 +7,7 @@
My Workers
My Graphs
Transactions
+ Notifications
{/if}
diff --git a/sql/issue_144_notification_upgrade.sql b/sql/issue_144_notification_upgrade.sql
new file mode 100644
index 00000000..e2884e9e
--- /dev/null
+++ b/sql/issue_144_notification_upgrade.sql
@@ -0,0 +1,6 @@
+ALTER TABLE `notifications` ADD `account_id` INT UNSIGNED NULL DEFAULT NULL , ADD INDEX ( `account_id` )
+CREATE TABLE IF NOT EXISTS `notification_settings` (
+ `type` varchar(15) NOT NULL,
+ `account_id` int(11) NOT NULL,
+ `active` tinyint(1) NOT NULL DEFAULT '0'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
From 4ea8b6c6950a4cf7d2b8246d410f82ddb2de414c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 14:26:18 +0200
Subject: [PATCH 068/168] Adding new notification system for new blocks
* Modified findblocks cron
* Modified notifications cron for new structure
* Improved notification class
* Added new template for new_block type
* Moved idle_worker type template
* Added new_block type to notification settings
---
cronjobs/findblock.php | 10 +++++
cronjobs/notifications.php | 11 +----
public/include/classes/mail.class.php | 8 ++--
public/include/classes/notification.class.php | 42 ++++++++++++++++++-
.../mail/{ => notifications}/idle_worker.tpl | 0
.../mail/notifications/new_block.tpl | 7 ++++
.../mmcFE/account/notifications/default.tpl | 7 ++++
7 files changed, 71 insertions(+), 14 deletions(-)
rename public/templates/mail/{ => notifications}/idle_worker.tpl (100%)
create mode 100644 public/templates/mail/notifications/new_block.tpl
diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php
index 2f978eed..d52c1cc9 100755
--- a/cronjobs/findblock.php
+++ b/cronjobs/findblock.php
@@ -112,6 +112,16 @@ foreach ($aAllBlocks as $iIndex => $aBlock) {
. $strStatus
. "\n"
);
+
+ // Notify users
+ $aAccounts = $notification->getNotificationByType('new_block');
+ foreach ($aAccounts as $account_id) {
+ $aMailData = $aBlock;
+ $aMailData['subject'] = 'New Block';
+ $aMailData['email'] = $user->getUserEmail($user->getUserName($account_id));
+ $aMailData['shares'] = $iRoundShares;
+ $notification->sendNotification($account_id, 'new_block', $aMailData);
+ }
}
}
?>
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
index eddef3de..cd8c020a 100755
--- a/cronjobs/notifications.php
+++ b/cronjobs/notifications.php
@@ -32,15 +32,8 @@ if (empty($aWorkers)) {
$aData['username'] = $user->getUserName($aWorker['account_id']);
$aData['subject'] = 'IDLE Worker : ' . $aWorker['username'];
$aData['email'] = $user->getUserEmail($aData['username']);
- if ( $notification->isNotified($aData) ) {
- verbose("Worker already notified\n");
- continue;
- }
- if ($notification->addNotification($aWorker['account_id'], 'idle_worker', $aData) && $notification->sendMail($aData['email'], 'idle_worker', $aData)) {
- verbose ("Notified " . $aData['email'] . " for IDLE worker " . $aWorker['username'] . "\n");
- } else {
- verbose("Unable to send notification: " . $notification->getError() . "\n");
- }
+ if (!$notification->sendNotification($aWorker['account_id'], 'idle_worker', $aData))
+ verbose($notification->getError() . "\n");
}
}
diff --git a/public/include/classes/mail.class.php b/public/include/classes/mail.class.php
index 2800500c..e34423c5 100644
--- a/public/include/classes/mail.class.php
+++ b/public/include/classes/mail.class.php
@@ -16,6 +16,9 @@ class Mail {
public function setSmarty($smarty) {
$this->smarty = $smarty;
}
+ public function setUser($user) {
+ $this->user = $user;
+ }
public function setConfig($config) {
$this->config = $config;
}
@@ -35,14 +38,14 @@ class Mail {
return true;
}
- public function sendMail($email, $template, $aData) {
+ public function sendMail($template, $aData) {
$this->smarty->assign('WEBSITENAME', $this->config['website']['name']);
$this->smarty->assign('SUBJECT', $aData['subject']);
$this->smarty->assign('DATA', $aData);
$headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
- if (mail($email,
+ if (mail($aData['email'],
$this->smarty->fetch(BASEPATH . 'templates/mail/subject.tpl'),
$this->smarty->fetch(BASEPATH . 'templates/mail/' . $template . '.tpl'),
$headers)) {
@@ -61,5 +64,4 @@ $mail->setDebug($debug);
$mail->setMysql($mysqli);
$mail->setSmarty($smarty);
$mail->setConfig($config);
-
?>
diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php
index cff05abb..d324d4a7 100644
--- a/public/include/classes/notification.class.php
+++ b/public/include/classes/notification.class.php
@@ -44,7 +44,6 @@ class Notification extends Mail {
return true;
// Catchall
// Does not seem to have a notification set
- $this->setErrorMessage("Unable to run query: " . $this->mysqli->error);
return false;
}
@@ -73,7 +72,7 @@ class Notification extends Mail {
if ($stmt && $stmt->bind_param('iss', $account_id, $type, $data) && $stmt->execute())
return true;
$this->debug->append("Failed to add notification for $type with $data: " . $this->mysqli->error);
- $this->setErrorMessage("Unable to add new notification");
+ $this->setErrorMessage("Unable to add new notification " . $this->mysqli->error);
return false;
}
@@ -109,6 +108,21 @@ class Notification extends Mail {
return false;
}
+ /**
+ * Get all accounts that wish to receive a specific notification
+ * @param strType string Notification type
+ * @return data array User Accounts
+ **/
+ public function getNotificationAccountIdByType($strType) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ $stmt = $this->mysqli->prepare("SELECT account_id FROM $this->tableSettings WHERE type = ? AND active = 1");
+ if ($stmt && $stmt->bind_param('s', $strType) && $stmt->execute() && $result = $stmt->get_result()) {
+ return $result->fetch_all(MYSQLI_ASSOC);
+ }
+ // Catchall
+ return false;
+ }
+
/**
* Update accounts notification settings
* @param account_id int Account ID
@@ -144,6 +158,28 @@ class Notification extends Mail {
}
return true;
}
+
+ /**
+ * Send a specific notification setup in notification_settings
+ * @param type string Notification type
+ * @return bool
+ **/
+ public function sendNotification($account_id, $strType, $aMailData) {
+ // Check if we notified for this event already
+ if ( $this->isNotified($aMailData) ) {
+ $this->setErrorMessage('A notification for this event has been sent already');
+ return false;
+ }
+ // Check if this user wants strType notifications
+ $stmt = $this->mysqli->prepare("SELECT account_id FROM $this->tableSettings WHERE type = ? AND active = 1 AND account_id = ?");
+ if ($stmt && $stmt->bind_param('si', $strType, $account_id) && $stmt->execute() && $stmt->bind_result($id) && $stmt->fetch()) {
+ if ($stmt->close() && $this->sendMail('notifications/' . $strType, $aMailData) && $this->addNotification($account_id, $strType, $aMailData))
+ return true;
+ } else {
+ $this->setErrorMessage('User disabled ' . $strType . ' notifications');
+ }
+ return false;
+ }
}
$notification = new Notification();
@@ -151,3 +187,5 @@ $notification->setDebug($debug);
$notification->setMysql($mysqli);
$notification->setSmarty($smarty);
$notification->setConfig($config);
+
+?>
diff --git a/public/templates/mail/idle_worker.tpl b/public/templates/mail/notifications/idle_worker.tpl
similarity index 100%
rename from public/templates/mail/idle_worker.tpl
rename to public/templates/mail/notifications/idle_worker.tpl
diff --git a/public/templates/mail/notifications/new_block.tpl b/public/templates/mail/notifications/new_block.tpl
new file mode 100644
index 00000000..9d17d06e
--- /dev/null
+++ b/public/templates/mail/notifications/new_block.tpl
@@ -0,0 +1,7 @@
+
+
+A new block has been discovered!
+
+
+
+
diff --git a/public/templates/mmcFE/account/notifications/default.tpl b/public/templates/mmcFE/account/notifications/default.tpl
index 1b737f79..94c0c2b0 100644
--- a/public/templates/mmcFE/account/notifications/default.tpl
+++ b/public/templates/mmcFE/account/notifications/default.tpl
@@ -8,6 +8,13 @@
Type
Active
+
+ IDLE Worker
+
+
+
+
+
New Blocks
From 79d9c9714dfbfe590b894bd21dc5c445faea6d6e Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 14:31:00 +0200
Subject: [PATCH 069/168] wrong method call
---
cronjobs/findblock.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php
index d52c1cc9..ead4b61c 100755
--- a/cronjobs/findblock.php
+++ b/cronjobs/findblock.php
@@ -114,9 +114,9 @@ foreach ($aAllBlocks as $iIndex => $aBlock) {
);
// Notify users
- $aAccounts = $notification->getNotificationByType('new_block');
+ $aAccounts = $notification->getNotificationAccountIdByType('new_block');
foreach ($aAccounts as $account_id) {
- $aMailData = $aBlock;
+ $aMailData['height'] = $aBlock['height'];
$aMailData['subject'] = 'New Block';
$aMailData['email'] = $user->getUserEmail($user->getUserName($account_id));
$aMailData['shares'] = $iRoundShares;
From d723f4e8ef36e55fccfacece4d3dbe8fa143c6a9 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 15:17:14 +0200
Subject: [PATCH 070/168] Adding notification on automatic payout
* Added new mail template
* Added notification code to auto_payout cron
---
cronjobs/auto_payout.php | 15 ++++++++++++---
.../templates/mail/notifications/auto_payout.tpl | 8 ++++++++
2 files changed, 20 insertions(+), 3 deletions(-)
create mode 100644 public/templates/mail/notifications/auto_payout.tpl
diff --git a/cronjobs/auto_payout.php b/cronjobs/auto_payout.php
index 36c8a873..48861c86 100755
--- a/cronjobs/auto_payout.php
+++ b/cronjobs/auto_payout.php
@@ -52,19 +52,28 @@ if (! empty($users)) {
}
// Send balance, fees are reduced later
- try {
+/* try {
$bitcoin->sendtoaddress($aUserData['coin_address'], $dBalance);
} catch (BitcoinClientException $e) {
verbose("SEND FAILED\n");
continue;
}
-
+ */
// Create transaction record
if ($transaction->addTransaction($aUserData['id'], $dBalance, 'Debit_AP', NULL, $aUserData['coin_address'], 0.1)) {
- verbose("OK\n");
+ // Notify user via mail
+ $aMailData['email'] = $user->getUserEmail($user->getUserName($aUserData['id']));
+ $aMailData['subject'] = 'Auto Payout Completed';
+ $aMailData['amount'] = $dBalance;
+ if (!$notification->sendNotification($aUserData['id'], 'auto_payout', $aMailData)) {
+ verbose("NOTIFY FAILED\n");
+ } else {
+ verbose("OK\n");
+ }
} else {
verbose("FAILED\n");
}
+
} else {
verbose("SKIPPED\n");
}
diff --git a/public/templates/mail/notifications/auto_payout.tpl b/public/templates/mail/notifications/auto_payout.tpl
new file mode 100644
index 00000000..6d045357
--- /dev/null
+++ b/public/templates/mail/notifications/auto_payout.tpl
@@ -0,0 +1,8 @@
+
+
+An automated payout completed.
+Amount: {$DATA.amount}
+
+
+
+
From b2b853d3e0d693289c0f4482d6ebb2b73f259590 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 15:24:58 +0200
Subject: [PATCH 071/168] Added manual payout notification
* Added mail template for manual payouts
* Added code to account page to notify via mail on payout
* Added new option to notification setting template
Adds another feature to #144
---
public/include/pages/account/edit.inc.php | 9 +++++++--
.../mail/notifications/manual_payout.tpl | 8 ++++++++
.../mmcFE/account/notifications/default.tpl | 15 ++++++++++++++-
3 files changed, 29 insertions(+), 3 deletions(-)
create mode 100644 public/templates/mail/notifications/manual_payout.tpl
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index 1e2941bb..446c13f1 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -36,12 +36,17 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
}
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send LTC, please contact site support immidiately', 'TYPE' => 'errormsg');
- $continue = false;
+// $continue = false;
}
}
// Set balance to 0, add to paid out, insert to ledger
- if ($continue == true && $transaction->addTransaction($_SESSION['USERDATA']['id'], $dBalance, 'Debit_MP', NULL, $sCoinAddress))
+ if ($continue == true && $transaction->addTransaction($_SESSION['USERDATA']['id'], $dBalance, 'Debit_MP', NULL, $sCoinAddress)) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Transaction completed', 'TYPE' => 'success');
+ $aMailData['email'] = $user->getUserEmail($user->getUserName($_SESSION['USERDATA']['id']));
+ $aMailData['amount'] = $dBalance;
+ $aMailData['subject'] = 'Manual Payout Completed';
+ $notification->sendNotification($_SESSION['USERDATA']['id'], 'manual_payout', $aMailData);
+ }
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service', 'TYPE' => 'errormsg');
}
diff --git a/public/templates/mail/notifications/manual_payout.tpl b/public/templates/mail/notifications/manual_payout.tpl
new file mode 100644
index 00000000..75198d7b
--- /dev/null
+++ b/public/templates/mail/notifications/manual_payout.tpl
@@ -0,0 +1,8 @@
+
+
+An manual payout request completed.
+Amount: {$DATA.amount}
+
+
+
+
diff --git a/public/templates/mmcFE/account/notifications/default.tpl b/public/templates/mmcFE/account/notifications/default.tpl
index 94c0c2b0..676807d3 100644
--- a/public/templates/mmcFE/account/notifications/default.tpl
+++ b/public/templates/mmcFE/account/notifications/default.tpl
@@ -29,6 +29,13 @@
+
+ Manual Payout
+
+
+
+
+
@@ -55,7 +62,13 @@
{$NOTIFICATIONS[notification].id}
{$NOTIFICATIONS[notification].time}
- {$NOTIFICATIONS[notification].type}
+
+ {if $NOTIFICATIONS[notification].type == new_block}New Block
+ {else if $NOTIFICATIONS[notification].type == auto_payout}Auto Payout
+ {else if $NOTIFICATIONS[notification].type == idle_worker}IDLE Worker
+ {else if $NOTIFICATIONS[notification].type == manual_payout}Manual Payout
+ {/if}
+
From af9d2aed9534fc535546c42a4c9a6c614343e737 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 15:31:38 +0200
Subject: [PATCH 072/168] wrong syntax in upgrade SQL
---
sql/issue_144_notification_upgrade.sql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sql/issue_144_notification_upgrade.sql b/sql/issue_144_notification_upgrade.sql
index e2884e9e..a47f3bbf 100644
--- a/sql/issue_144_notification_upgrade.sql
+++ b/sql/issue_144_notification_upgrade.sql
@@ -1,4 +1,4 @@
-ALTER TABLE `notifications` ADD `account_id` INT UNSIGNED NULL DEFAULT NULL , ADD INDEX ( `account_id` )
+ALTER TABLE `notifications` ADD `account_id` INT UNSIGNED NULL DEFAULT NULL , ADD INDEX ( `account_id` );
CREATE TABLE IF NOT EXISTS `notification_settings` (
`type` varchar(15) NOT NULL,
`account_id` int(11) NOT NULL,
From 3bc5c68403f5de3d977ab9405c3242e7bc43e42c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 16:09:32 +0200
Subject: [PATCH 073/168] Updated SQL Files
* Updated upgrade SQL
* Added full new structure
---
sql/issue_144_notification_upgrade.sql | 1 +
sql/mmcfe_ng_structure.sql | 30 +++++++++++++++++++-------
2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/sql/issue_144_notification_upgrade.sql b/sql/issue_144_notification_upgrade.sql
index a47f3bbf..fd7ae177 100644
--- a/sql/issue_144_notification_upgrade.sql
+++ b/sql/issue_144_notification_upgrade.sql
@@ -1,4 +1,5 @@
ALTER TABLE `notifications` ADD `account_id` INT UNSIGNED NULL DEFAULT NULL , ADD INDEX ( `account_id` );
+ALTER TABLE `notifications` CHANGE `time` `time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
CREATE TABLE IF NOT EXISTS `notification_settings` (
`type` varchar(15) NOT NULL,
`account_id` int(11) NOT NULL,
diff --git a/sql/mmcfe_ng_structure.sql b/sql/mmcfe_ng_structure.sql
index 039b9a04..1e21bbf4 100644
--- a/sql/mmcfe_ng_structure.sql
+++ b/sql/mmcfe_ng_structure.sql
@@ -3,7 +3,7 @@
-- http://www.phpmyadmin.net
--
-- Host: localhost
--- Generation Time: Jun 07, 2013 at 03:39 PM
+-- Generation Time: Jun 09, 2013 at 04:08 PM
-- Server version: 5.5.31-0ubuntu0.13.04.1
-- PHP Version: 5.4.9-4ubuntu2
@@ -65,7 +65,7 @@ CREATE TABLE IF NOT EXISTS `blocks` (
PRIMARY KEY (`id`),
UNIQUE KEY `height` (`height`,`blockhash`),
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';
-- --------------------------------------------------------
@@ -74,14 +74,28 @@ CREATE TABLE IF NOT EXISTS `blocks` (
--
CREATE TABLE IF NOT EXISTS `notifications` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`type` varchar(25) NOT NULL,
`data` varchar(255) NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '1',
- `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `account_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `active` (`active`),
- KEY `data` (`data`)
+ KEY `data` (`data`),
+ KEY `account_id` (`account_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `notification_settings`
+--
+
+CREATE TABLE IF NOT EXISTS `notification_settings` (
+ `type` varchar(15) NOT NULL,
+ `account_id` int(11) NOT NULL,
+ `active` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -153,7 +167,7 @@ CREATE TABLE IF NOT EXISTS `shares_archive` (
PRIMARY KEY (`id`),
UNIQUE KEY `share_id` (`share_id`),
KEY `time` (`time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
-- --------------------------------------------------------
@@ -170,7 +184,7 @@ CREATE TABLE IF NOT EXISTS `statistics_shares` (
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`),
KEY `block_id` (`block_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -190,7 +204,7 @@ CREATE TABLE IF NOT EXISTS `transactions` (
KEY `block_id` (`block_id`),
KEY `account_id` (`account_id`),
KEY `type` (`type`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
From bbffdeb689bca15b96abf07027df9558965da71e Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 16:38:12 +0200
Subject: [PATCH 074/168] Allow pagination on Transaction page
* Added pager to all three transaction tables
* Added two additional pagination definitions to JS
* Added pagination ID to pagination template
---
public/site_assets/mmcFE/js/custom.js | 6 ++++++
public/templates/mmcFE/account/transactions/default.tpl | 9 ++++++---
public/templates/mmcFE/global/pagination.tpl | 2 +-
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/public/site_assets/mmcFE/js/custom.js b/public/site_assets/mmcFE/js/custom.js
index 2070bd82..fcecd8e7 100644
--- a/public/site_assets/mmcFE/js/custom.js
+++ b/public/site_assets/mmcFE/js/custom.js
@@ -69,6 +69,12 @@ $(function () {
$("table.pagesort")
.tablesorter({ widgets: ['zebra'] })
.tablesorterPager({ positionFixed: false, container: $("#pager") });
+ $("table.pagesort2")
+ .tablesorter({ widgets: ['zebra'] })
+ .tablesorterPager({ positionFixed: false, container: $("#pager2") });
+ $("table.pagesort4")
+ .tablesorter({ widgets: ['zebra'] })
+ .tablesorterPager({ positionFixed: false, container: $("#pager3") });
$('.block table tr th.header').css('cursor', 'pointer');
diff --git a/public/templates/mmcFE/account/transactions/default.tpl b/public/templates/mmcFE/account/transactions/default.tpl
index 8f5282e1..88f749c1 100644
--- a/public/templates/mmcFE/account/transactions/default.tpl
+++ b/public/templates/mmcFE/account/transactions/default.tpl
@@ -1,7 +1,8 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Transaction Log" BUTTONS=array(Confirmed,Unconfirmed,Orphan)}
-
+ {include file="global/pagination.tpl"}
+
@@ -42,7 +43,8 @@
-
+ {include file="global/pagination.tpl" ID=2}
+
@@ -86,7 +88,8 @@
-
+ {include file="global/pagination.tpl"}
+
diff --git a/public/templates/mmcFE/global/pagination.tpl b/public/templates/mmcFE/global/pagination.tpl
index 0bae6db5..22bdb0e3 100644
--- a/public/templates/mmcFE/global/pagination.tpl
+++ b/public/templates/mmcFE/global/pagination.tpl
@@ -1,4 +1,4 @@
-
{/if}
{/section}
From 2c4bf7d4aa237deca0c760f212371b9389bb3c21 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:31:35 +0200
Subject: [PATCH 077/168] properly format payout and round it
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index a71c42a3..1dafa288 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -44,7 +44,7 @@ verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
- $aData['payout'] = $aData['valid'] * $pps_value;
+ $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8));
// Defaults
$aData['fee' ] = 0;
From e62a3527dbeae989ba9a34c7b211b777df1c188c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:34:02 +0200
Subject: [PATCH 078/168] forgot 8 decimals
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index 1dafa288..bef78f2a 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -44,7 +44,7 @@ verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
- $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8));
+ $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8), 8);
// Defaults
$aData['fee' ] = 0;
From 638e33e52534840afadebd4be6a46f66ddffb79f Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:45:53 +0200
Subject: [PATCH 079/168] properly format pps value to 12 digits
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index bef78f2a..e2804595 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -31,7 +31,7 @@ if ( $bitcoin->can_connect() === true ){
}
// Value per share calculation
-$pps_value = 50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']);
+$pps_value = number_format(round(50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']), 12) ,12);
// Find our last share accounted and last inserted share for PPS calculations
$iPreviousShareId = $setting->getValue('pps_last_share_id');
From 20c3d771e6e3e88f42015c3b9dbd970bffa4eb21 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:48:09 +0200
Subject: [PATCH 080/168] moved table header to the left
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index e2804595..427035d5 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -40,7 +40,7 @@ $iLastShareId = $share->getLastInsertedShareId();
// Check for all new shares, we start one higher as our last accounted share to avoid duplicates
$aAccountShares = $share->getSharesForAccounts($iPreviousShareId + 1, $iLastShareId);
-verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\t\tStatus\n");
+verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\tPayout\t\tDonation\tFee\t\tStatus\n");
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
From ae0252d927153d08e4338fca34c7f26765eae783 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 17:29:38 +0200
Subject: [PATCH 081/168] adding PPS value to sidebard
---
public/include/smarty_globals.inc.php | 6 ++++++
public/templates/mmcFE/global/sidebar.tpl | 13 +++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index fa5c7923..d37e45cc 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -12,12 +12,18 @@ $aRoundShares = $statistics->getRoundShares();
$iCurrentActiveWorkers = $worker->getCountAllActiveWorkers();
$iCurrentPoolHashrate = $statistics->getCurrentHashrate();
$iCurrentPoolShareRate = $statistics->getCurrentShareRate();
+if ($bitcoin->can_connect() === true){
+ $dDifficulty = $bitcoin->query('getdifficulty');
+} else {
+ $dDifficulty = 1;
+}
$aGlobal = array(
'slogan' => $config['website']['slogan'],
'websitename' => $config['website']['name'],
'hashrate' => $iCurrentPoolHashrate,
'sharerate' => $iCurrentPoolShareRate,
+ 'ppsvalue' => number_format(round(50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']), 12) ,12),
'workers' => $iCurrentActiveWorkers,
'roundshares' => $aRoundShares,
'fees' => $config['fees'],
diff --git a/public/templates/mmcFE/global/sidebar.tpl b/public/templates/mmcFE/global/sidebar.tpl
index 21a8e0aa..05f6e00e 100644
--- a/public/templates/mmcFE/global/sidebar.tpl
+++ b/public/templates/mmcFE/global/sidebar.tpl
@@ -6,8 +6,17 @@
From b1d698e6864d2a9c0386c430b147e09fb1d5e8bc Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 10 Jun 2013 10:54:57 +0200
Subject: [PATCH 089/168] Allow users to change their email address
* Added email to account page
* No confirmation required as of yet
Fixes #142
---
public/include/classes/user.class.php | 19 +++++++++++--------
public/include/pages/account/edit.inc.php | 2 +-
.../templates/mmcFE/account/edit/default.tpl | 1 +
3 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 7f919502..feb0466f 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -238,7 +238,7 @@ class User {
* @param donat float donation % of income
* @return bool
**/
- public function updateAccount($userID, $address, $threshold, $donate) {
+ public function updateAccount($userID, $address, $threshold, $donate, $email) {
$this->debug->append("STA " . __METHOD__, 4);
$bUser = false;
@@ -257,18 +257,21 @@ class User {
$this->setErrorMessage('Donation above allowed 100% limit');
return false;
}
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ $this->setErrorMessage('Invalid email address');
+ return false;
+ }
// Number sanitizer, just in case we fall through above
$threshold = min($this->config['ap_threshold']['max'], max(0, floatval($threshold)));
$donate = min(100, max(0, floatval($donate)));
// We passed all validation checks so update the account
- $stmt = $this->mysqli->prepare("UPDATE $this->table SET coin_address = ?, ap_threshold = ?, donate_percent = ? WHERE id = ?");
- $stmt->bind_param('sddi', $address, $threshold, $donate, $userID);
- $stmt->execute();
- if ( $stmt->errno == 0 ) {
- $stmt->close();
+ $stmt = $this->mysqli->prepare("UPDATE $this->table SET coin_address = ?, ap_threshold = ?, donate_percent = ?, email = ? WHERE id = ?");
+ if ($this->checkStmt($stmt) && $stmt->bind_param('sddsi', $address, $threshold, $donate, $email, $userID) && $stmt->execute())
return true;
- }
+ // Catchall
+ $this->setErrorMessage('Failed to update your account');
+ $this->debug->append('Account update failed: ' . $this->mysqli->error);
return false;
}
@@ -356,7 +359,7 @@ class User {
$this->debug->append("Fetching user information for user id: $userID");
$stmt = $this->mysqli->prepare("
SELECT
- id, username, pin, api_key, admin,
+ id, username, pin, api_key, admin, email,
IFNULL(donate_percent, '0') as donate_percent, coin_address, ap_threshold
FROM $this->table
WHERE id = ? LIMIT 0,1");
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index e47ad6dd..8d8b1a3d 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -62,7 +62,7 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
break;
case 'updateAccount':
- if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'])) {
+ if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'], $_POST['email'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'errormsg');
diff --git a/public/templates/mmcFE/account/edit/default.tpl b/public/templates/mmcFE/account/edit/default.tpl
index 2fc9b4a9..31352e54 100644
--- a/public/templates/mmcFE/account/edit/default.tpl
+++ b/public/templates/mmcFE/account/edit/default.tpl
@@ -7,6 +7,7 @@
Username: {$GLOBAL.userdata.username}
User Id: {$GLOBAL.userdata.id}
API Key: {$GLOBAL.userdata.api_key}
+ E-Mail:
Payment Address:
Donation %: [donation amount in percent (example: 0.5)]
Automatic Payout Threshold: [{$GLOBAL.config.ap_threshold.min}-{$GLOBAL.config.ap_threshold.max} LTC. Set to '0' for no auto payout]
From 31de069533811ebb478079de708088ffc2aafd4e Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 10 Jun 2013 11:28:20 +0200
Subject: [PATCH 090/168] Changed getLockedBalance and added SQL
* New SQL file for upgrade includes next changes
* Properly calculate getLockedBalance based on shares
Further addresses #70
---
public/include/classes/transaction.class.php | 16 +++++++++++-----
sql/issue_70_transactions_upgrade.sql | 1 +
2 files changed, 12 insertions(+), 5 deletions(-)
create mode 100644 sql/issue_70_transactions_upgrade.sql
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index 939684c4..4b304797 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -143,8 +143,11 @@ class Transaction {
SELECT sum(t.amount) AS credit
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type IN ('Credit', 'Credit_PPS')
- AND b.confirmations >= " . $this->config['confirmations'] . "
+ WHERE
+ (
+ ( t.type = 'Credit' AND b.confirmations >= ? ) OR
+ ( t.type = 'Credit_PPS' )
+ )
) AS t1,
(
SELECT sum(t.amount) AS debit
@@ -155,10 +158,13 @@ class Transaction {
SELECT sum(t.amount) AS other
FROM " . $this->table . " AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type IN ('Donation','Fee','Donation_PPS','Fee_PPS')
- AND b.confirmations >= " . $this->config['confirmations'] . "
+ WHERE
+ (
+ ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
+ ( t.type IN ('Donation_PPS', 'Fee_PPS') )
+ )
) AS t3");
- if ($this->checkStmt($stmt) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
+ if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $this->config['confirmations'], $this->config['confirmations']) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
return $dBalance;
// Catchall
$this->setErrorMessage('Unable to find locked credits for all users');
diff --git a/sql/issue_70_transactions_upgrade.sql b/sql/issue_70_transactions_upgrade.sql
new file mode 100644
index 00000000..90561397
--- /dev/null
+++ b/sql/issue_70_transactions_upgrade.sql
@@ -0,0 +1 @@
+ALTER TABLE `transactions` CHANGE `type` `type` ENUM( 'Credit', 'Debit_MP', 'Debit_AP', 'Donation', 'Fee', 'Orphan_Credit', 'Orphan_Fee', 'Orphan_Donation', 'Bonus', 'Orphan_Bonus', 'Credit_PPS', 'Debit_PPS', 'Donation_PPS' ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
From ea9f6b2c9a88269801c811135ca3155237671575 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 10 Jun 2013 11:34:20 +0200
Subject: [PATCH 091/168] Adding new config option `payout_system`
* Change templates based on the payout system used
* Modified sidebar for new PPS method
Further addresses #70
---
public/include/config/global.inc.dist.php | 1 +
public/include/smarty_globals.inc.php | 1 +
public/templates/mmcFE/global/sidebar.tpl | 6 ++++++
3 files changed, 8 insertions(+)
diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php
index 306d5261..7e3415f9 100644
--- a/public/include/config/global.inc.dist.php
+++ b/public/include/config/global.inc.dist.php
@@ -34,6 +34,7 @@ $config = array(
'slogan' => 'Resistance is futile',
'email' => 'test@example.com', // Mail address used for notifications
),
+ 'payout_system' => 'pps', // Set your payout here so template changes are activated
'archive_shares' => true, // Store accounted shares in archive table?
'blockexplorer' => 'http://explorer.litecoin.net/search?q=', // URL for block searches, prefixed to each block number
'chaininfo' => 'http://allchains.info', // Link to Allchains for Difficulty information
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index d37e45cc..209f6a71 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -33,6 +33,7 @@ $aGlobal = array(
'blockexplorer' => $config['blockexplorer'],
'chaininfo' => $config['chaininfo'],
'config' => array(
+ 'payout_system' => $config['payout_system'],
'ap_threshold' => array(
'min' => $config['ap_threshold']['min'],
'max' => $config['ap_threshold']['max']
diff --git a/public/templates/mmcFE/global/sidebar.tpl b/public/templates/mmcFE/global/sidebar.tpl
index 05f6e00e..e6736e1a 100644
--- a/public/templates/mmcFE/global/sidebar.tpl
+++ b/public/templates/mmcFE/global/sidebar.tpl
@@ -13,10 +13,13 @@
Hashrate
{$GLOBAL.userdata.hashrate|number_format} KH/s
+{if $GLOBAL.config.payout_system == 'pps'}
PPS Value
{$GLOBAL.ppsvalue}
+{/if}
+{if $GLOBAL.config.payout_system != 'pps'}
Unpaid Shares
@@ -28,6 +31,7 @@
Pool Valid
{$GLOBAL.roundshares.valid|number_format}
+{/if}
Round Shares
@@ -43,6 +47,7 @@
Your Invalid
{$GLOBAL.userdata.shares.invalid|number_format}
+{if $GLOBAL.config.payout_system != 'pps'}
LTC Round Estimate
@@ -62,6 +67,7 @@
Payout
{$GLOBAL.userdata.est_payout|number_format:"3"}
+{/if}
Account Balance
{$GLOBAL.userdata.balance|default:"0"} LTC
From 31e51061f7f6fca8f961377c225c0bf836b6383b Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 10 Jun 2013 11:53:44 +0200
Subject: [PATCH 092/168] archive/purge accounted PPS shares
---
cronjobs/pps_payout.php | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index 427035d5..efdbfc94 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -84,4 +84,22 @@ foreach ($aAccountShares as $aData) {
$setting->setValue('pps_last_share_id', $iLastShareId);
verbose("\n\n------------------------------------------------------------------------------------\n\n");
+
+// Fetch all unaccounted blocks
+$aAllBlocks = $block->getAllUnaccounted('ASC');
+if (empty($aAllBlocks)) {
+ verbose("No new unaccounted blocks found\n");
+}
+
+// Go through blocks and archive/delete shares that have been accounted for
+foreach ($aAllBlocks as $iIndex => $aBlock) {
+ $dummy = $iIndex - 1;
+ if ($config['archive_shares'] && $aBlock['share_id'] < $iLastShareId) {
+ $share->moveArchive($aBlock['share_id'], $aBlock['id'], @$aAllBlocks[$dummy]['share_id']);
+ }
+ if ($aBlock['share_id'] < $iLastShareId && !$share->deleteAccountedShares($aBlock['share_id'], @$aAllBlocks[$dummy]['share_id'])) {
+ verbose("\nERROR : Failed to delete accounted shares from " . $aBlock['share_id'] . " to " . @$aAllBlocks[$dummy]['share_id'] . ", aborting!\n");
+ exit(1);
+ }
+}
?>
From 56f3d57c35b82f041801f94dfdb242b7e4a43761 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 10 Jun 2013 18:37:14 +0200
Subject: [PATCH 093/168] further improved checkboxes
---
public/site_assets/mmcFE/css/style.css | 22 +++++++++++++++++++
.../mmcFE/account/workers/default.tpl | 5 ++++-
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/public/site_assets/mmcFE/css/style.css b/public/site_assets/mmcFE/css/style.css
index 8133150a..6243fbfc 100644
--- a/public/site_assets/mmcFE/css/style.css
+++ b/public/site_assets/mmcFE/css/style.css
@@ -1038,3 +1038,25 @@ a:hover {
padding-left:5px;
}
+/* Custom checkboxes */
+input[type=checkbox] {
+ display:none;
+}
+
+input[type=checkbox] + label
+{
+ background: url('../images/error.gif');
+ height: 16px;
+ width: 16px;
+ display:inline-block;
+ padding: 0 0 0 0px;
+}
+
+input[type=checkbox]:checked + label
+{
+ background: url('../images/success.gif');
+ height: 16px;
+ width: 16px;
+ display:inline-block;
+ padding: 0 0 0 0px;
+}
diff --git a/public/templates/mmcFE/account/workers/default.tpl b/public/templates/mmcFE/account/workers/default.tpl
index 612bd227..8c127400 100644
--- a/public/templates/mmcFE/account/workers/default.tpl
+++ b/public/templates/mmcFE/account/workers/default.tpl
@@ -21,7 +21,10 @@
{$username.0|escape}.
-
+
+
+
+
{$WORKERS[worker].hashrate|number_format}
Delete
From 4745a2f6f8cbd168bad6c8cd9efeab17aefa7725 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 21:37:14 +0200
Subject: [PATCH 094/168] Adding support for PPS payout method
This commit changed a few things in the backend and classes code:
* Any _PPS transaction does NOT need to be confirmed
* Queries updated for added _PPS transactions
* Template updated to properly display these transactions
Cronjob
* Added pps_payput cron to run payouts based on worker submitted shares
* **IMPORTANT**: Can NOT be run with proportional_payout!
Addresses #70
---
cronjobs/pps_payout.php | 87 +++++++++++++++++++
public/include/classes/share.class.php | 15 ++++
public/include/classes/transaction.class.php | 28 ++++--
.../mmcFE/account/transactions/default.tpl | 5 +-
4 files changed, 125 insertions(+), 10 deletions(-)
create mode 100755 cronjobs/pps_payout.php
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
new file mode 100755
index 00000000..a71c42a3
--- /dev/null
+++ b/cronjobs/pps_payout.php
@@ -0,0 +1,87 @@
+#!/usr/bin/php
+can_connect() === true ){
+ $dDifficulty = $bitcoin->getdifficulty();
+} else {
+ verbose("Aborted: " . $bitcoin->can_connect() . "\n");
+ exit(1);
+}
+
+// Value per share calculation
+$pps_value = 50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']);
+
+// Find our last share accounted and last inserted share for PPS calculations
+$iPreviousShareId = $setting->getValue('pps_last_share_id');
+$iLastShareId = $share->getLastInsertedShareId();
+
+// Check for all new shares, we start one higher as our last accounted share to avoid duplicates
+$aAccountShares = $share->getSharesForAccounts($iPreviousShareId + 1, $iLastShareId);
+
+verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\t\tStatus\n");
+
+foreach ($aAccountShares as $aData) {
+ // Take our valid shares and multiply by per share value
+ $aData['payout'] = $aData['valid'] * $pps_value;
+
+ // Defaults
+ $aData['fee' ] = 0;
+ $aData['donation'] = 0;
+
+ // Calculate block fees
+ if ($config['fees'] > 0)
+ $aData['fee'] = number_format(round($config['fees'] / 100 * $aData['payout'], 8), 8);
+ // Calculate donation amount
+ $aData['donation'] = number_format(round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8), 8);
+
+ verbose($aData['id'] . "\t" .
+ $aData['username'] . "\t" .
+ $aData['invalid'] . "\t" .
+ $aData['valid'] . "\t*\t" .
+ $pps_value . "\t=\t" .
+ $aData['payout'] . "\t" .
+ $aData['donation'] . "\t" .
+ $aData['fee'] . "\t");
+
+ $strStatus = "OK";
+ // Add new credit transaction
+ if (!$transaction->addTransaction($aData['id'], $aData['payout'], 'Credit_PPS'))
+ $strStatus = "Transaction Failed";
+ // Add new fee debit for this block
+ if ($aData['fee'] > 0 && $config['fees'] > 0)
+ if (!$transaction->addTransaction($aData['id'], $aData['fee'], 'Fee_PPS'))
+ $strStatus = "Fee Failed";
+ // Add new donation debit
+ if ($aData['donation'] > 0)
+ if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation_PPS'))
+ $strStatus = "Donation Failed";
+ verbose($strStatus . "\n");
+}
+
+// Store our last inserted ID for the next run
+$setting->setValue('pps_last_share_id', $iLastShareId);
+
+verbose("\n\n------------------------------------------------------------------------------------\n\n");
+?>
diff --git a/public/include/classes/share.class.php b/public/include/classes/share.class.php
index b0a3b249..1033f92c 100644
--- a/public/include/classes/share.class.php
+++ b/public/include/classes/share.class.php
@@ -44,6 +44,21 @@ class Share {
return $this->table;
}
+ /**
+ * Get last inserted Share ID from Database
+ * Used for PPS calculations without moving to archive
+ **/
+ public function getLastInsertedShareId() {
+ $stmt = $this->mysqli->prepare("
+ SELECT MAX(id) AS id FROM $this->table
+ ");
+ if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
+ return $result->fetch_object()->id;
+ // Catchall
+ $this->setErrorMessage('Failed to fetch last inserted share ID');
+ return false;
+ }
+
/**
* Get all valid shares for this round
* @param previous_upstream int Previous found share accepted by upstream to limit results
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index d12d14ee..f1c9907c 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -131,8 +131,10 @@ class Transaction {
SELECT sum(t.amount) AS credit
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type IN ('Credit','Bonus')
- AND b.confirmations >= " . $this->config['confirmations'] . "
+ WHERE (
+ ( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR
+ t.type = 'Credit_PPS'
+ )
) AS t1,
(
SELECT sum(t.amount) AS debit
@@ -143,10 +145,12 @@ class Transaction {
SELECT sum(t.amount) AS other
FROM " . $this->table . " AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type IN ('Donation','Fee')
- AND b.confirmations >= " . $this->config['confirmations'] . "
+ WHERE (
+ ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
+ t.type IN ('Donation_PPS','Fee_PPS')
+ )
) AS t3");
- if ($this->checkStmt($stmt) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
+ if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $this->config['confirmations'], $this->config['confirmations']) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
return $dBalance;
// Catchall
$this->setErrorMessage('Unable to find locked credits for all users');
@@ -168,8 +172,11 @@ class Transaction {
SELECT sum(t.amount) AS credit
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type IN ('Credit','Bonus')
- AND b.confirmations >= ?
+ WHERE
+ (
+ ( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR
+ ( t.type = 'Credit_PPS' )
+ )
AND t.account_id = ?
) AS t1,
(
@@ -182,8 +189,11 @@ class Transaction {
SELECT sum(t.amount) AS other
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
- WHERE t.type IN ('Donation','Fee')
- AND b.confirmations >= ?
+ WHERE
+ (
+ ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
+ ( t.type IN ('Donation_PPS', 'Fee_PPS') )
+ )
AND t.account_id = ?
) AS t3
");
diff --git a/public/templates/mmcFE/account/transactions/default.tpl b/public/templates/mmcFE/account/transactions/default.tpl
index 2e6ae074..d2393450 100644
--- a/public/templates/mmcFE/account/transactions/default.tpl
+++ b/public/templates/mmcFE/account/transactions/default.tpl
@@ -19,6 +19,9 @@
(($TRANSACTIONS[transaction].type == 'Credit' or $TRANSACTIONS[transaction].type == 'Bonus')and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Donation' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Fee' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
+ or $TRANSACTIONS[transaction].type == 'Credit_PPS'
+ or $TRANSACTIONS[transaction].type == 'Fee_PPS'
+ or $TRANSACTIONS[transaction].type == 'Donation_PPS'
or $TRANSACTIONS[transaction].type == 'Debit_AP'
or $TRANSACTIONS[transaction].type == 'Debit_MP'
)}
@@ -28,7 +31,7 @@
{$TRANSACTIONS[transaction].type}
{$TRANSACTIONS[transaction].coin_address}
{if $TRANSACTIONS[transaction].height == 0}n/a{else}{$TRANSACTIONS[transaction].height}{/if}
- {$TRANSACTIONS[transaction].amount}
+ {$TRANSACTIONS[transaction].amount}
{/if}
{/section}
From 4acf1194184a4753dc01c1dd9adae7ef117efa94 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:31:35 +0200
Subject: [PATCH 095/168] properly format payout and round it
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index a71c42a3..1dafa288 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -44,7 +44,7 @@ verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
- $aData['payout'] = $aData['valid'] * $pps_value;
+ $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8));
// Defaults
$aData['fee' ] = 0;
From 3f8a1ea0f7a86ee247f2b5b9a1ab581f0c64ca8c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:34:02 +0200
Subject: [PATCH 096/168] forgot 8 decimals
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index 1dafa288..bef78f2a 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -44,7 +44,7 @@ verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
- $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8));
+ $aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8), 8);
// Defaults
$aData['fee' ] = 0;
From cb3e02e896f37cbef2ac55d239edb4cd5862ac90 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:45:53 +0200
Subject: [PATCH 097/168] properly format pps value to 12 digits
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index bef78f2a..e2804595 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -31,7 +31,7 @@ if ( $bitcoin->can_connect() === true ){
}
// Value per share calculation
-$pps_value = 50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']);
+$pps_value = number_format(round(50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']), 12) ,12);
// Find our last share accounted and last inserted share for PPS calculations
$iPreviousShareId = $setting->getValue('pps_last_share_id');
From 41b35a2d962240408669b6d9a611e02841e4785a Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 6 Jun 2013 23:48:09 +0200
Subject: [PATCH 098/168] moved table header to the left
---
cronjobs/pps_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index e2804595..427035d5 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -40,7 +40,7 @@ $iLastShareId = $share->getLastInsertedShareId();
// Check for all new shares, we start one higher as our last accounted share to avoid duplicates
$aAccountShares = $share->getSharesForAccounts($iPreviousShareId + 1, $iLastShareId);
-verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\t\tPayout\t\tDonation\tFee\t\tStatus\n");
+verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\tPayout\t\tDonation\tFee\t\tStatus\n");
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
From 666fde91b6d0a9863cc57e39aeff9b62947fae4f Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Sun, 9 Jun 2013 17:29:38 +0200
Subject: [PATCH 099/168] adding PPS value to sidebard
---
public/include/smarty_globals.inc.php | 6 ++++++
public/templates/mmcFE/global/sidebar.tpl | 13 +++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index fa5c7923..d37e45cc 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -12,12 +12,18 @@ $aRoundShares = $statistics->getRoundShares();
$iCurrentActiveWorkers = $worker->getCountAllActiveWorkers();
$iCurrentPoolHashrate = $statistics->getCurrentHashrate();
$iCurrentPoolShareRate = $statistics->getCurrentShareRate();
+if ($bitcoin->can_connect() === true){
+ $dDifficulty = $bitcoin->query('getdifficulty');
+} else {
+ $dDifficulty = 1;
+}
$aGlobal = array(
'slogan' => $config['website']['slogan'],
'websitename' => $config['website']['name'],
'hashrate' => $iCurrentPoolHashrate,
'sharerate' => $iCurrentPoolShareRate,
+ 'ppsvalue' => number_format(round(50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']), 12) ,12),
'workers' => $iCurrentActiveWorkers,
'roundshares' => $aRoundShares,
'fees' => $config['fees'],
diff --git a/public/templates/mmcFE/global/sidebar.tpl b/public/templates/mmcFE/global/sidebar.tpl
index 21a8e0aa..05f6e00e 100644
--- a/public/templates/mmcFE/global/sidebar.tpl
+++ b/public/templates/mmcFE/global/sidebar.tpl
@@ -6,8 +6,17 @@
From 27b4c4473f6578d633caa51d236c6066c0e82e49 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 12 Jun 2013 09:17:50 +0200
Subject: [PATCH 110/168] Adding bonus to unconfirmed calculations
---
public/include/classes/transaction.class.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index d4f0b203..3609de73 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -204,7 +204,7 @@ class Transaction {
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE
(
- ( t.type = 'Credit' AND b.confirmations < ? ) OR
+ ( t.type IN ('Credit','Bonus') AND b.confirmations < ? ) OR
( t.type = 'Credit_PPS' )
)
AND t.account_id = ?
From 8ef44f79dbc5624d7afa60f0437df2d70474fa7e Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 12 Jun 2013 11:19:07 +0200
Subject: [PATCH 111/168] Fixing column name in settings table
* This will change the name in the settings table for old installations
Fixes #167
---
sql/issue_167_settings_upgrade.sql | 1 +
1 file changed, 1 insertion(+)
create mode 100644 sql/issue_167_settings_upgrade.sql
diff --git a/sql/issue_167_settings_upgrade.sql b/sql/issue_167_settings_upgrade.sql
new file mode 100644
index 00000000..dff0378a
--- /dev/null
+++ b/sql/issue_167_settings_upgrade.sql
@@ -0,0 +1 @@
+ALTER TABLE `settings` CHANGE `setting` `name` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ;
From 4d513318831c14b025a8e1566425426f6dd80103 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 12 Jun 2013 11:31:37 +0200
Subject: [PATCH 112/168] trying new layout for stats page
---
public/include/pages/statistics/pool.inc.php | 2 +-
.../mmcFE/statistics/blocks/blocks_found.tpl | 18 +++++++++---------
.../mmcFE/statistics/pool/authenticated.tpl | 4 ++--
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/public/include/pages/statistics/pool.inc.php b/public/include/pages/statistics/pool.inc.php
index ede0933a..76014fe4 100644
--- a/public/include/pages/statistics/pool.inc.php
+++ b/public/include/pages/statistics/pool.inc.php
@@ -21,7 +21,7 @@ $aContributorsShares = $statistics->getTopContributors('shares', 15);
$aContributorsHashes = $statistics->getTopContributors('hashes', 15);
// Grab the last 10 blocks found
-$iLimit = 10;
+$iLimit = 5;
$aBlocksFoundData = $statistics->getBlocksFound($iLimit);
$aBlockData = $aBlocksFoundData[0];
diff --git a/public/templates/mmcFE/statistics/blocks/blocks_found.tpl b/public/templates/mmcFE/statistics/blocks/blocks_found.tpl
index 474fd87c..2278fb3c 100644
--- a/public/templates/mmcFE/statistics/blocks/blocks_found.tpl
+++ b/public/templates/mmcFE/statistics/blocks/blocks_found.tpl
@@ -3,27 +3,27 @@
- Block
- Validity
- Finder
- Date / Time
- Difficulty
- Shares
+ Block
+ Validity
+ Finder
+ Time
+ Difficulty
+ Shares
{assign var=rank value=1}
{section block $BLOCKSFOUND}
- {$BLOCKSFOUND[block].height}
-
+ {$BLOCKSFOUND[block].height}
+
{if $BLOCKSFOUND[block].confirmations >= $GLOBAL.confirmations}
Confirmed
{else if $BLOCKSFOUND[block].confirmations == -1}
Orphan
{else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if}
{$BLOCKSFOUND[block].finder|default:"unknown"}
- {$BLOCKSFOUND[block].time|date_format:"%d/%m/%Y %H:%M:%S"}
+ {$BLOCKSFOUND[block].time|date_format:"%d/%m/%Y %H:%M:%S"}
{$BLOCKSFOUND[block].difficulty|number_format:"8"}
{$BLOCKSFOUND[block].shares|number_format}
diff --git a/public/templates/mmcFE/statistics/pool/authenticated.tpl b/public/templates/mmcFE/statistics/pool/authenticated.tpl
index f8530cd7..5d21e3eb 100644
--- a/public/templates/mmcFE/statistics/pool/authenticated.tpl
+++ b/public/templates/mmcFE/statistics/pool/authenticated.tpl
@@ -4,7 +4,7 @@
{include file="statistics/pool/contributors_hashrate.tpl"}
-{include file="global/block_header.tpl" BLOCK_HEADER="Server Stats" BLOCK_STYLE="clear:all;" STYLE="padding-left:5px;padding-right:5px;"}
+{include file="global/block_header.tpl" ALIGN="left" BLOCK_HEADER="Server Stats" BLOCK_STYLE="clear:all;" STYLE="padding-left:5px;padding-right:5px;"}
@@ -44,6 +44,6 @@
{include file="global/block_footer.tpl"}
-{include file="statistics/blocks/blocks_found.tpl"}
+{include file="statistics/blocks/blocks_found.tpl" ALIGN="right"}
{include file="global/block_footer.tpl"}
From 1b850ae67c22ec54a60b8603d891a2304ee86312 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 12 Jun 2013 12:04:44 +0200
Subject: [PATCH 113/168] Changing default statistics URL to pool
Fixes #170
---
public/templates/mmcFE/global/navigation.tpl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/templates/mmcFE/global/navigation.tpl b/public/templates/mmcFE/global/navigation.tpl
index 3f26387a..84da0388 100644
--- a/public/templates/mmcFE/global/navigation.tpl
+++ b/public/templates/mmcFE/global/navigation.tpl
@@ -19,7 +19,7 @@
{/if}
- Statistics
+ Statistics
Pool Stats
{if $smarty.session.AUTHENTICATED|default}Block Stats {/if}
From baed854bc9509f63138f2da98c3c65dc0a6e96fc Mon Sep 17 00:00:00 2001
From: lhpool
Date: Wed, 12 Jun 2013 19:22:40 +0200
Subject: [PATCH 114/168] Added Usd/Day
Added Est Usd/Day to stats
---
.../templates/mmcFE/statistics/pool/contributors_hashrate.tpl | 3 +++
1 file changed, 3 insertions(+)
diff --git a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
index 232a5ab0..37e6e6a8 100644
--- a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
+++ b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
@@ -7,6 +7,7 @@
User Name
KH/s
Ł/Day (est)
+ Usd/Day (est)
@@ -19,6 +20,7 @@
{$CONTRIBHASHES[contrib].account}
{$CONTRIBHASHES[contrib].hashrate|number_format}
{$estday|number_format:"3"}
+ {$estday|number_format:"3"*$GLOBAL.price|default:"n/a"|number_format:"4"}
{/section}
{if $listed != 1}
@@ -27,6 +29,7 @@
{$GLOBAL.userdata.username}
{$GLOBAL.userdata.hashrate}
{$estday|number_format:"3"}
+ {$estday|number_format:"3"*$GLOBAL.price|default:"n/a"|number_format:"4"}
{/if}
From 13fc01243e56bd9499616db7f6c89bec9f1b9b7c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 12 Jun 2013 13:36:44 +0200
Subject: [PATCH 115/168] Adding configurable currency name to global config
Addresses #138
---
public/include/config/global.inc.dist.php | 1 +
public/include/pages/account/edit.inc.php | 6 +++---
public/include/smarty_globals.inc.php | 2 ++
public/templates/mmcFE/account/edit/default.tpl | 6 +++---
public/templates/mmcFE/global/header.tpl | 2 +-
public/templates/mmcFE/global/sidebar.tpl | 8 ++++----
.../mmcFE/statistics/pool/contributors_hashrate.tpl | 4 ++--
7 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php
index df743132..934df25d 100644
--- a/public/include/config/global.inc.dist.php
+++ b/public/include/config/global.inc.dist.php
@@ -34,6 +34,7 @@ $config = array(
'slogan' => 'Resistance is futile',
'email' => 'test@example.com', // Mail address used for notifications
),
+ 'currency' => 'LTC', // Currency name to be used on website
'block_bonus' => 0,
'payout_system' => 'prop', // Set your payout here so template changes are activated
'archive_shares' => true, // Store accounted shares in archive table?
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index 345816a7..968ecfbe 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -21,7 +21,7 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
$aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
$dBalance = $aBalance['confirmed'];
$sCoinAddress = $user->getCoinAddress($_SESSION['USERDATA']['id']);
- // Ensure we can cover the potential transaction fee of 0.1 LTC with the balance
+ // Ensure we can cover the potential transaction fee of 0.1 with the balance
if ($dBalance > 0.1) {
if ($bitcoin->can_connect() === true) {
try {
@@ -40,7 +40,7 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
$continue = false;
}
} catch (BitcoinClientException $e) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send LTC, please contact site support immidiately', 'TYPE' => 'errormsg');
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send ' . $config['currency'] . ', please contact site support immidiately', 'TYPE' => 'errormsg');
$continue = false;
}
}
@@ -56,7 +56,7 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service', 'TYPE' => 'errormsg');
}
} else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than 0.1 LTC to cover transaction fees', 'TYPE' => 'errormsg');
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than 0.1 ' . $conifg['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg');
}
$setting->setValue('manual_payout_active', 0);
}
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index 209f6a71..950f1db6 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -18,6 +18,7 @@ if ($bitcoin->can_connect() === true){
$dDifficulty = 1;
}
+// Global data for Smarty
$aGlobal = array(
'slogan' => $config['website']['slogan'],
'websitename' => $config['website']['name'],
@@ -33,6 +34,7 @@ $aGlobal = array(
'blockexplorer' => $config['blockexplorer'],
'chaininfo' => $config['chaininfo'],
'config' => array(
+ 'currency' => $config['currency'],
'payout_system' => $config['payout_system'],
'ap_threshold' => array(
'min' => $config['ap_threshold']['min'],
diff --git a/public/templates/mmcFE/account/edit/default.tpl b/public/templates/mmcFE/account/edit/default.tpl
index 86f4f02d..e5c31eab 100644
--- a/public/templates/mmcFE/account/edit/default.tpl
+++ b/public/templates/mmcFE/account/edit/default.tpl
@@ -10,20 +10,20 @@
E-Mail:
Payment Address:
Donation %: [donation amount in percent (example: 0.5)]
- Automatic Payout Threshold: [{$GLOBAL.config.ap_threshold.min}-{$GLOBAL.config.ap_threshold.max} LTC. Set to '0' for no auto payout]
+ Automatic Payout Threshold: [{$GLOBAL.config.ap_threshold.min}-{$GLOBAL.config.ap_threshold.max} {$GLOBAL.config.currency}. Set to '0' for no auto payout]
4 digit PIN: [The 4 digit PIN you chose when registering]
{include file="global/block_footer.tpl"}
{include file="global/block_header.tpl" BLOCK_HEADER="Cash Out"}
- Please note: a 0.1 ltc transaction will apply when processing "On-Demand" manual payments
+ Please note: a 0.1 {$GLOBAL.config.currency} transaction will apply when processing "On-Demand" manual payments
diff --git a/public/templates/mmcFE/global/header.tpl b/public/templates/mmcFE/global/header.tpl
index 126fde52..a4b23f4b 100644
--- a/public/templates/mmcFE/global/header.tpl
+++ b/public/templates/mmcFE/global/header.tpl
@@ -4,7 +4,7 @@
- LTC/usd: {$GLOBAL.price|default:"n/a"|number_format:"4"}
+ {$GLOBAL.config.currency}/usd: {$GLOBAL.price|default:"n/a"|number_format:"4"}
Pool Hashrate: {($GLOBAL.hashrate / 1000)|number_format:"3"} MH/s
Pool Sharerate: {$GLOBAL.sharerate|number_format:"2"} Shares/s
Pool Workers: {$GLOBAL.workers}
diff --git a/public/templates/mmcFE/global/sidebar.tpl b/public/templates/mmcFE/global/sidebar.tpl
index 6049f9ac..34018785 100644
--- a/public/templates/mmcFE/global/sidebar.tpl
+++ b/public/templates/mmcFE/global/sidebar.tpl
@@ -49,7 +49,7 @@
{if $GLOBAL.config.payout_system != 'pps'}
- LTC Round Estimate
+ {$GLOBAL.config.currency} Round Estimate
Block
@@ -69,9 +69,9 @@
{/if}
- Account Balance
- Confirmed {$GLOBAL.userdata.balance.confirmed|default:"0"} LTC
- Unconfirmed {$GLOBAL.userdata.balance.unconfirmed|default:"0"} LTC
+ {$GLOBAL.config.currency} Account Balance
+ Confirmed {$GLOBAL.userdata.balance.confirmed|default:"0"}
+ Unconfirmed {$GLOBAL.userdata.balance.unconfirmed|default:"0"}
diff --git a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
index 37e6e6a8..67c8f5d7 100644
--- a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
+++ b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
@@ -6,8 +6,8 @@
Rank
User Name
KH/s
- Ł/Day (est)
- Usd/Day (est)
+ {$GLOBAL.config.currency}/Day
+ Usd/Day
From a2ad57e92aaa3c122017d8f657ed8b625b33d33e Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 12 Jun 2013 13:46:29 +0200
Subject: [PATCH 116/168] Adding configurable TX Fee for web interface
* This does not actually check the TX fee set on the RPC side
* Ensures TX fee is covered before doing transactions
* Display TX fee when required
Fixes #138
---
cronjobs/auto_payout.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/cronjobs/auto_payout.php b/cronjobs/auto_payout.php
index ca33dc3f..366298e1 100755
--- a/cronjobs/auto_payout.php
+++ b/cronjobs/auto_payout.php
@@ -43,7 +43,7 @@ if (! empty($users)) {
verbose($aUserData['id'] . "\t" . $aUserData['username'] . "\t" . $dBalance . "\t" . $aUserData['ap_threshold'] . "\t\t" . $aUserData['coin_address'] . "\t");
// Only run if balance meets threshold and can pay the potential transaction fee
- if ($dBalance > $aUserData['ap_threshold'] && $dBalance > 0.1) {
+ if ($dBalance > $aUserData['ap_threshold'] && $dBalance > $config['txfee']) {
// Validate address against RPC
try {
$bitcoin->validateaddress($aUserData['coin_address']);
@@ -52,7 +52,7 @@ if (! empty($users)) {
continue;
}
- // Send balance, fees are reduced later
+ // Send balance, fees are reduced later by RPC Server
try {
$bitcoin->sendtoaddress($aUserData['coin_address'], $dBalance);
} catch (BitcoinClientException $e) {
@@ -61,7 +61,7 @@ if (! empty($users)) {
}
// Create transaction record
- if ($transaction->addTransaction($aUserData['id'], $dBalance, 'Debit_AP', NULL, $aUserData['coin_address'], 0.1)) {
+ if ($transaction->addTransaction($aUserData['id'], $dBalance, 'Debit_AP', NULL, $aUserData['coin_address'])) {
// Notify user via mail
$aMailData['email'] = $user->getUserEmail($user->getUserName($aUserData['id']));
$aMailData['subject'] = 'Auto Payout Completed';
@@ -76,7 +76,7 @@ if (! empty($users)) {
}
} else {
- verbose("SKIPPED\n");
+ verbose("INSUFF_TXFEE\n");
}
}
} else {
From 8859f0c0915950ceadcc81ecff2d3b275d9009d4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 12 Jun 2013 13:51:10 +0200
Subject: [PATCH 117/168] forgot to add the actual files :/
---
public/include/config/global.inc.dist.php | 1 +
public/include/pages/account/edit.inc.php | 8 ++++----
public/include/smarty_globals.inc.php | 1 +
public/templates/mmcFE/account/edit/default.tpl | 2 +-
4 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php
index 934df25d..e8d12774 100644
--- a/public/include/config/global.inc.dist.php
+++ b/public/include/config/global.inc.dist.php
@@ -35,6 +35,7 @@ $config = array(
'email' => 'test@example.com', // Mail address used for notifications
),
'currency' => 'LTC', // Currency name to be used on website
+ 'txfee' => 0.1, // Default tx fee added by RPC server
'block_bonus' => 0,
'payout_system' => 'prop', // Set your payout here so template changes are activated
'archive_shares' => true, // Store accounted shares in archive table?
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index 968ecfbe..6726b7d9 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -21,8 +21,8 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
$aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
$dBalance = $aBalance['confirmed'];
$sCoinAddress = $user->getCoinAddress($_SESSION['USERDATA']['id']);
- // Ensure we can cover the potential transaction fee of 0.1 with the balance
- if ($dBalance > 0.1) {
+ // Ensure we can cover the potential transaction fee
+ if ($dBalance > $config['txfee']) {
if ($bitcoin->can_connect() === true) {
try {
$bitcoin->validateaddress($sCoinAddress);
@@ -31,7 +31,7 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
$continue = false;
}
if ($continue == true) {
- // Send balance to address, mind 0.1 fee for transaction!
+ // Send balance to address, mind fee for transaction!
try {
if ($setting->getValue('auto_payout_active') == 0) {
$bitcoin->sendtoaddress($sCoinAddress, $dBalance);
@@ -56,7 +56,7 @@ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service', 'TYPE' => 'errormsg');
}
} else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than 0.1 ' . $conifg['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg');
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than ' . $config['txfee'] . ' ' . $conifg['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg');
}
$setting->setValue('manual_payout_active', 0);
}
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index 950f1db6..8ec1e882 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -35,6 +35,7 @@ $aGlobal = array(
'chaininfo' => $config['chaininfo'],
'config' => array(
'currency' => $config['currency'],
+ 'txfee' => $config['txfee'],
'payout_system' => $config['payout_system'],
'ap_threshold' => array(
'min' => $config['ap_threshold']['min'],
diff --git a/public/templates/mmcFE/account/edit/default.tpl b/public/templates/mmcFE/account/edit/default.tpl
index e5c31eab..f48ef67f 100644
--- a/public/templates/mmcFE/account/edit/default.tpl
+++ b/public/templates/mmcFE/account/edit/default.tpl
@@ -17,7 +17,7 @@
{include file="global/block_footer.tpl"}
{include file="global/block_header.tpl" BLOCK_HEADER="Cash Out"}
- Please note: a 0.1 {$GLOBAL.config.currency} transaction will apply when processing "On-Demand" manual payments
+ Please note: a {$GLOBAL.config.txfee} {$GLOBAL.config.currency} transaction will apply when processing "On-Demand" manual payments
From 42b6d4b3b29751d91f56e4debf3519c1d26c7122 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Wed, 12 Jun 2013 12:57:18 +0200
Subject: [PATCH 118/168] Adding support for user locking
* Currently no GUI, use DB access to change the row entry
* Upgraded Database table `accounts` with upgrade SQL
* Updated `admin` field to `is_admin` as boolean
* Modified pages, classes, templates to support is_admin and is_locked
Addresses #147
---
public/include/classes/statistics.class.php | 3 +-
public/include/classes/user.class.php | 45 +++++--
public/include/pages/account.inc.php | 11 +-
public/include/pages/account/edit.inc.php | 122 +++++++++---------
.../pages/account/notifications.inc.php | 36 +++---
.../pages/account/transactions.inc.php | 13 +-
public/include/pages/account/workers.inc.php | 57 ++++----
public/include/pages/admin.inc.php | 7 +-
public/include/pages/admin/user.inc.php | 7 +-
public/include/pages/admin/wallet.inc.php | 7 +-
public/include/pages/login.inc.php | 2 +-
.../include/pages/statistics/blocks.inc.php | 11 +-
public/include/pages/statistics/pool.inc.php | 2 +-
public/include/pages/statistics/user.inc.php | 10 +-
public/templates/mmcFE/admin/user/default.tpl | 6 +-
public/templates/mmcFE/global/navigation.tpl | 2 +-
sql/issue_147_accounts_upgrade.sql | 2 +
17 files changed, 181 insertions(+), 162 deletions(-)
create mode 100644 sql/issue_147_accounts_upgrade.sql
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index a63416dd..3bcebcfb 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -185,7 +185,8 @@ class Statistics {
$stmt = $this->mysqli->prepare("
SELECT
a.id AS id,
- a.admin as admin,
+ a.is_admin as is_admin,
+ a.is_locked as is_locked,
a.username AS username,
a.donate_percent AS donate_percent,
a.email AS email,
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index feb0466f..76cfd1a4 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -36,7 +36,10 @@ class User {
return $this->getSingle($username, 'email', 'username', 's');
}
public function getUserAdmin($id) {
- return $this->getSingle($id, 'admin', 'id');
+ return $this->getSingle($id, 'is_admin', 'id');
+ }
+ public function getUserLocked($id) {
+ return $this->getSingle($id, 'is_locked', 'id');
}
public function getUserToken($id) {
return $this->getSingle($id, 'token', 'id');
@@ -44,9 +47,11 @@ class User {
public function getIdFromToken($token) {
return $this->getSingle($token, 'id', 'token', 's');
}
+ public function isLocked($id) {
+ return $this->getUserLocked($id);
+ }
public function isAdmin($id) {
- if ($this->getUserAdmin($id) == 1) return true;
- return false;
+ return $this->getUserAdmin($id);
}
public function setUserToken($id) {
@@ -79,10 +84,15 @@ class User {
public function checkLogin($username, $password) {
$this->debug->append("STA " . __METHOD__, 4);
$this->debug->append("Checking login for $username with password $password", 2);
- if ( $this->checkUserPassword($username, $password) ) {
+ if ($this->isLocked($this->getUserId($username))) {
+ $this->setErrorMessage("Account is locked. Please contact site support.");
+ return false;
+ }
+ if ( $this->checkUserPassword($username, $password)) {
$this->createSession($username);
return true;
}
+ $this->setErrorMessage("Invalid username or password");
return false;
}
@@ -300,7 +310,7 @@ class User {
private function checkUserPassword($username, $password) {
$this->debug->append("STA " . __METHOD__, 4);
$user = array();
- $stmt = $this->mysqli->prepare("SELECT username, id, admin FROM $this->table WHERE username=? AND pass=? LIMIT 1");
+ $stmt = $this->mysqli->prepare("SELECT username, id, is_admin FROM $this->table WHERE username=? AND pass=? LIMIT 1");
if ($this->checkStmt($stmt)) {
$stmt->bind_param('ss', $username, hash('sha256', $password.$this->salt));
$stmt->execute();
@@ -308,7 +318,7 @@ class User {
$stmt->fetch();
$stmt->close();
// Store the basic login information
- $this->user = array('username' => $row_username, 'id' => $row_id, 'admin' => $row_admin);
+ $this->user = array('username' => $row_username, 'id' => $row_id, 'is_admin' => $row_admin);
return $username === $row_username;
}
return false;
@@ -337,7 +347,8 @@ class User {
$this->debug->append("STA " . __METHOD__, 4);
session_destroy();
session_regenerate_id(true);
- return true;
+ // Enforce a page reload
+ header("Location: index.php");
}
/**
@@ -359,7 +370,7 @@ class User {
$this->debug->append("Fetching user information for user id: $userID");
$stmt = $this->mysqli->prepare("
SELECT
- id, username, pin, api_key, admin, email,
+ id, username, pin, api_key, is_admin, email,
IFNULL(donate_percent, '0') as donate_percent, coin_address, ap_threshold
FROM $this->table
WHERE id = ? LIMIT 0,1");
@@ -417,7 +428,7 @@ class User {
");
} else {
$stmt = $this->mysqli->prepare("
- INSERT INTO $this->table (username, pass, email, pin, api_key, admin)
+ INSERT INTO $this->table (username, pass, email, pin, api_key, is_admin)
VALUES (?, ?, ?, ?, ?, 1)
");
}
@@ -505,6 +516,22 @@ class User {
}
return false;
}
+
+ /**
+ * Check if a user is authenticated and allowed to login
+ * Checks the $_SESSION for existing data
+ * Destroys the session if account is now locked
+ * @param none
+ * @return bool
+ **/
+ public function isAuthenticated() {
+ $this->debug->append("STA " . __METHOD__, 4);
+ if ($_SESSION['AUTHENTICATED'] == true && ! $this->isLocked($_SESSION['USERDATA']['id']))
+ return true;
+ // Catchall
+ $this->logoutUser();
+ return false;
+ }
}
// Make our class available automatically
diff --git a/public/include/pages/account.inc.php b/public/include/pages/account.inc.php
index 859575d9..9e43518e 100644
--- a/public/include/pages/account.inc.php
+++ b/public/include/pages/account.inc.php
@@ -1,13 +1,10 @@
isAuthenticated()) {
+ // Tempalte specifics
+ $smarty->assign("CONTENT", "default.tpl");
}
-
-// Tempalte specifics
-$smarty->assign("CONTENT", "default.tpl");
?>
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index 6726b7d9..a4859c8f 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -4,79 +4,77 @@
if (!defined('SECURITY'))
die('Hacking attempt');
-if (!$_SESSION['AUTHENTICATED']) {
- header('Location: index.php?page=home');
-}
-
-if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST['do']) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN','TYPE' => 'errormsg');
-} else {
- switch ($_POST['do']) {
- case 'cashOut':
- if ($setting->getValue('manual_payout_active') == 1) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'A manual payout is in progress. Please try again later.', 'TYPE' => 'errormsg');
- } else {
- $setting->setValue('manual_payout_active', 1);
- $continue = true;
- $aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
- $dBalance = $aBalance['confirmed'];
- $sCoinAddress = $user->getCoinAddress($_SESSION['USERDATA']['id']);
- // Ensure we can cover the potential transaction fee
- if ($dBalance > $config['txfee']) {
- if ($bitcoin->can_connect() === true) {
- try {
- $bitcoin->validateaddress($sCoinAddress);
- } catch (BitcoinClientException $e) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid payment address: ' . $sUserSendAddress, 'TYPE' => 'errormsg');
- $continue = false;
- }
- if ($continue == true) {
- // Send balance to address, mind fee for transaction!
+if ($user->isAuthenticated()) {
+ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST['do']) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN','TYPE' => 'errormsg');
+ } else {
+ switch ($_POST['do']) {
+ case 'cashOut':
+ if ($setting->getValue('manual_payout_active') == 1) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'A manual payout is in progress. Please try again later.', 'TYPE' => 'errormsg');
+ } else {
+ $setting->setValue('manual_payout_active', 1);
+ $continue = true;
+ $aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
+ $dBalance = $aBalance['confirmed'];
+ $sCoinAddress = $user->getCoinAddress($_SESSION['USERDATA']['id']);
+ // Ensure we can cover the potential transaction fee
+ if ($dBalance > $config['txfee']) {
+ if ($bitcoin->can_connect() === true) {
try {
- if ($setting->getValue('auto_payout_active') == 0) {
- $bitcoin->sendtoaddress($sCoinAddress, $dBalance);
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Auto-payout active, please contact site support immidiately to revoke invalid transactions.', 'TYPE' => 'errormsg');
- $continue = false;
- }
+ $bitcoin->validateaddress($sCoinAddress);
} catch (BitcoinClientException $e) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send ' . $config['currency'] . ', please contact site support immidiately', 'TYPE' => 'errormsg');
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid payment address: ' . $sUserSendAddress, 'TYPE' => 'errormsg');
$continue = false;
}
- }
- // Set balance to 0, add to paid out, insert to ledger
- if ($continue == true && $transaction->addTransaction($_SESSION['USERDATA']['id'], $dBalance, 'Debit_MP', NULL, $sCoinAddress)) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Transaction completed', 'TYPE' => 'success');
- $aMailData['email'] = $user->getUserEmail($user->getUserName($_SESSION['USERDATA']['id']));
- $aMailData['amount'] = $dBalance;
- $aMailData['subject'] = 'Manual Payout Completed';
- $notification->sendNotification($_SESSION['USERDATA']['id'], 'manual_payout', $aMailData);
+ if ($continue == true) {
+ // Send balance to address, mind fee for transaction!
+ try {
+ if ($setting->getValue('auto_payout_active') == 0) {
+ $bitcoin->sendtoaddress($sCoinAddress, $dBalance);
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Auto-payout active, please contact site support immidiately to revoke invalid transactions.', 'TYPE' => 'errormsg');
+ $continue = false;
+ }
+ } catch (BitcoinClientException $e) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send ' . $config['currency'] . ', please contact site support immidiately', 'TYPE' => 'errormsg');
+ $continue = false;
+ }
+ }
+ // Set balance to 0, add to paid out, insert to ledger
+ if ($continue == true && $transaction->addTransaction($_SESSION['USERDATA']['id'], $dBalance, 'Debit_MP', NULL, $sCoinAddress)) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Transaction completed', 'TYPE' => 'success');
+ $aMailData['email'] = $user->getUserEmail($user->getUserName($_SESSION['USERDATA']['id']));
+ $aMailData['amount'] = $dBalance;
+ $aMailData['subject'] = 'Manual Payout Completed';
+ $notification->sendNotification($_SESSION['USERDATA']['id'], 'manual_payout', $aMailData);
+ }
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service', 'TYPE' => 'errormsg');
}
} else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service', 'TYPE' => 'errormsg');
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than ' . $config['txfee'] . ' ' . $conifg['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg');
}
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than ' . $config['txfee'] . ' ' . $conifg['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg');
+ $setting->setValue('manual_payout_active', 0);
}
- $setting->setValue('manual_payout_active', 0);
- }
- break;
+ break;
- case 'updateAccount':
- if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'], $_POST['email'])) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'errormsg');
- }
- break;
+ case 'updateAccount':
+ if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'], $_POST['email'])) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'errormsg');
+ }
+ break;
- case 'updatePassword':
- if ($user->updatePassword($_SESSION['USERDATA']['id'], $_POST['currentPassword'], $_POST['newPassword'], $_POST['newPassword2'])) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'success');
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
+ case 'updatePassword':
+ if ($user->updatePassword($_SESSION['USERDATA']['id'], $_POST['currentPassword'], $_POST['newPassword'], $_POST['newPassword2'])) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'success');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
+ }
+ break;
}
- break;
}
}
diff --git a/public/include/pages/account/notifications.inc.php b/public/include/pages/account/notifications.inc.php
index 2ab9c0d0..87fd6217 100644
--- a/public/include/pages/account/notifications.inc.php
+++ b/public/include/pages/account/notifications.inc.php
@@ -2,24 +2,24 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
-if (!$_SESSION['AUTHENTICATED']) header('Location: index.php?page=home');
-
-if ($_REQUEST['do'] == 'save') {
- if ($notification->updateSettings($_SESSION['USERDATA']['id'], $_REQUEST['data'])) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Updated notification settings');
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update settings', 'TYPE' => 'errormsg');
+if ($user->isAuthenticated()) {
+ if ($_REQUEST['do'] == 'save') {
+ if ($notification->updateSettings($_SESSION['USERDATA']['id'], $_REQUEST['data'])) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Updated notification settings');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update settings', 'TYPE' => 'errormsg');
+ }
}
+
+ // Fetch notifications
+ $aNotifications = $notification->getNofifications($_SESSION['USERDATA']['id']);
+ if (!$aNotifications) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any notifications', 'TYPE' => 'errormsg');
+
+ // Fetch user notification settings
+ $aSettings = $notification->getNotificationSettings($_SESSION['USERDATA']['id']);
+
+ $smarty->assign('NOTIFICATIONS', $aNotifications);
+ $smarty->assign('SETTINGS', $aSettings);
+ $smarty->assign('CONTENT', 'default.tpl');
}
-
-// Fetch notifications
-$aNotifications = $notification->getNofifications($_SESSION['USERDATA']['id']);
-if (!$aNotifications) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any notifications', 'TYPE' => 'errormsg');
-
-// Fetch user notification settings
-$aSettings = $notification->getNotificationSettings($_SESSION['USERDATA']['id']);
-
-$smarty->assign('NOTIFICATIONS', $aNotifications);
-$smarty->assign('SETTINGS', $aSettings);
-$smarty->assign('CONTENT', 'default.tpl');
?>
diff --git a/public/include/pages/account/transactions.inc.php b/public/include/pages/account/transactions.inc.php
index 6e83e292..f6bdbfb2 100644
--- a/public/include/pages/account/transactions.inc.php
+++ b/public/include/pages/account/transactions.inc.php
@@ -2,11 +2,10 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
-if (!$_SESSION['AUTHENTICATED']) header('Location: index.php?page=home');
-
-$aTransactions = $transaction->getTransactions($_SESSION['USERDATA']['id']);
-if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'errormsg');
-
-$smarty->assign('TRANSACTIONS', $aTransactions);
-$smarty->assign('CONTENT', 'default.tpl');
+if (!$user->isAuthenticated()) {
+ $aTransactions = $transaction->getTransactions($_SESSION['USERDATA']['id']);
+ if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'errormsg');
+ $smarty->assign('TRANSACTIONS', $aTransactions);
+ $smarty->assign('CONTENT', 'default.tpl');
+}
?>
diff --git a/public/include/pages/account/workers.inc.php b/public/include/pages/account/workers.inc.php
index 67bd0e19..78556424 100644
--- a/public/include/pages/account/workers.inc.php
+++ b/public/include/pages/account/workers.inc.php
@@ -2,35 +2,36 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
-if (!$_SESSION['AUTHENTICATED']) header('Location: index.php?page=home');
-switch ($_REQUEST['do']) {
-case 'delete':
- if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed');
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
+if ($user->isAuthenticated()) {
+ switch ($_REQUEST['do']) {
+ case 'delete':
+ if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
+ }
+ break;
+ case 'add':
+ if ($worker->addWorker($_SESSION['USERDATA']['id'], $_POST['username'], $_POST['password'])) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Worker added');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
+ }
+ break;
+ case 'update':
+ if ($worker->updateWorkers($_SESSION['USERDATA']['id'], $_POST['data'])) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Worker updated');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
+ }
+ break;
}
- break;
-case 'add':
- if ($worker->addWorker($_SESSION['USERDATA']['id'], $_POST['username'], $_POST['password'])) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Worker added');
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
- }
- break;
-case 'update':
- if ($worker->updateWorkers($_SESSION['USERDATA']['id'], $_POST['data'])) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Worker updated');
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
- }
- break;
+
+ $aWorkers = $worker->getWorkers($_SESSION['USERDATA']['id']);
+ if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'errormsg');
+
+ $smarty->assign('CONTENT', 'default.tpl');
+ $smarty->assign('WORKERS', $aWorkers);
}
-
-$aWorkers = $worker->getWorkers($_SESSION['USERDATA']['id']);
-if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'errormsg');
-
-$smarty->assign('CONTENT', 'default.tpl');
-$smarty->assign('WORKERS', $aWorkers);
?>
diff --git a/public/include/pages/admin.inc.php b/public/include/pages/admin.inc.php
index 4409a769..5305b030 100644
--- a/public/include/pages/admin.inc.php
+++ b/public/include/pages/admin.inc.php
@@ -1,13 +1,12 @@
isAdmin($_SESSION['USERDATA']['id'])) {
+if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) {
header("HTTP/1.1 404 Page not found");
- die();
+ die("404 Page not found");
}
// Tempalte specifics
diff --git a/public/include/pages/admin/user.inc.php b/public/include/pages/admin/user.inc.php
index 8b40ab21..548cdf3a 100644
--- a/public/include/pages/admin/user.inc.php
+++ b/public/include/pages/admin/user.inc.php
@@ -1,13 +1,12 @@
isAdmin($_SESSION['USERDATA']['id'])) {
+if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) {
header("HTTP/1.1 404 Page not found");
- die();
+ die("404 Page not found");
}
$aRoundShares = $statistics->getRoundShares();
diff --git a/public/include/pages/admin/wallet.inc.php b/public/include/pages/admin/wallet.inc.php
index cb094fe9..45ff5af4 100644
--- a/public/include/pages/admin/wallet.inc.php
+++ b/public/include/pages/admin/wallet.inc.php
@@ -1,13 +1,12 @@
isAdmin($_SESSION['USERDATA']['id'])) {
+if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) {
header("HTTP/1.1 404 Page not found");
- die();
+ die("404 Page not found");
}
if ($bitcoin->can_connect() === true){
diff --git a/public/include/pages/login.inc.php b/public/include/pages/login.inc.php
index 6600a872..c157d720 100644
--- a/public/include/pages/login.inc.php
+++ b/public/include/pages/login.inc.php
@@ -7,7 +7,7 @@ if (!defined('SECURITY'))
if ( $user->checkLogin($_POST['username'],$_POST['password']) ) {
header('Location: index.php?page=home');
} else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid username or password', 'TYPE' => 'errormsg');
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '. $user->getError(), 'TYPE' => 'errormsg');
}
$smarty->assign('CONTENT', 'default.tpl');
?>
diff --git a/public/include/pages/statistics/blocks.inc.php b/public/include/pages/statistics/blocks.inc.php
index 7ba0bfdd..69bbade7 100644
--- a/public/include/pages/statistics/blocks.inc.php
+++ b/public/include/pages/statistics/blocks.inc.php
@@ -1,9 +1,8 @@
isAuthenticated()) header("Location: index.php?page=home");
// Grab the last blocks found
$iLimit = 30;
@@ -14,9 +13,5 @@ $aBlockData = $aBlocksFoundData[0];
$smarty->assign("BLOCKSFOUND", $aBlocksFoundData);
$smarty->assign("BLOCKLIMIT", $iLimit);
-if ($_SESSION['AUTHENTICATED']) {
- $smarty->assign("CONTENT", "blocks_found.tpl");
-} else {
- $smarty->assign("CONTENT", "default.tpl");
-}
+$smarty->assign("CONTENT", "blocks_found.tpl");
?>
diff --git a/public/include/pages/statistics/pool.inc.php b/public/include/pages/statistics/pool.inc.php
index 76014fe4..fc546e72 100644
--- a/public/include/pages/statistics/pool.inc.php
+++ b/public/include/pages/statistics/pool.inc.php
@@ -50,7 +50,7 @@ $smarty->assign("LASTBLOCK", $aBlockData['height']);
$smarty->assign("DIFFICULTY", $dDifficulty);
$smarty->assign("REWARD", $config['reward']);
-if ($_SESSION['AUTHENTICATED']) {
+if ($user->isAuthenticated()) {
$smarty->assign("CONTENT", "authenticated.tpl");
} else {
$smarty->assign("CONTENT", "../default.tpl");
diff --git a/public/include/pages/statistics/user.inc.php b/public/include/pages/statistics/user.inc.php
index 2b0b0ed9..13b3ba5b 100644
--- a/public/include/pages/statistics/user.inc.php
+++ b/public/include/pages/statistics/user.inc.php
@@ -4,12 +4,10 @@
if (!defined('SECURITY'))
die('Hacking attempt');
-$aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']);
-
-// Propagate content our template
-$smarty->assign("YOURHASHRATES", $aHourlyHashRates);
-
-if ($_SESSION['AUTHENTICATED']) {
+if ($user->isAuthenticated()) {
+ $aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']);
+ // Propagate content our template
+ $smarty->assign("YOURHASHRATES", $aHourlyHashRates);
$smarty->assign("CONTENT", "default.tpl");
}
?>
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 86c52e48..1da8c3a4 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -23,6 +23,7 @@
Est. Payout
Balance
Admin
+ Locked
@@ -37,7 +38,10 @@
{$USERS[user].payout.est_payout|number_format:"8"}
{$USERS[user].balance|number_format:"8"}
-
+
+
+
+
{sectionelse}
diff --git a/public/templates/mmcFE/global/navigation.tpl b/public/templates/mmcFE/global/navigation.tpl
index 84da0388..9beb87cb 100644
--- a/public/templates/mmcFE/global/navigation.tpl
+++ b/public/templates/mmcFE/global/navigation.tpl
@@ -11,7 +11,7 @@
{/if}
- {if $smarty.session.AUTHENTICATED|default:"0" == 1 && $GLOBAL.userdata.admin == 1}
+ {if $smarty.session.AUTHENTICATED|default:"0" == 1 && $GLOBAL.userdata.is_admin == 1}
Admin Panel
User Info
diff --git a/sql/issue_147_accounts_upgrade.sql b/sql/issue_147_accounts_upgrade.sql
new file mode 100644
index 00000000..ecff0f6f
--- /dev/null
+++ b/sql/issue_147_accounts_upgrade.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `accounts` ADD `is_locked` BOOLEAN NOT NULL DEFAULT FALSE AFTER `email` ;
+ALTER TABLE `accounts` CHANGE `admin` `is_admin` BOOLEAN NOT NULL DEFAULT FALSE ;
From 44851e35df9007abacb1ad3eddec0fafb168b47c Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 11:23:02 +0200
Subject: [PATCH 119/168] Add admin/lock changes to admin panel
* Add clickable boxes for Admin and Locked status for all users
* Change status via Ajax call, script embedded to the admin page
Fixes #147
---
public/include/classes/user.class.php | 16 +++++++++++
public/include/pages/admin/user.inc.php | 12 +++++++++
public/templates/mmcFE/admin/user/default.tpl | 27 ++++++++++++++++---
3 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 76cfd1a4..cc8d7c70 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -53,6 +53,22 @@ class User {
public function isAdmin($id) {
return $this->getUserAdmin($id);
}
+ public function changeLocked($id) {
+ $field = array(
+ 'name' => 'is_locked',
+ 'type' => 'i',
+ 'value' => !$this->isLocked($id)
+ );
+ return $this->updateSingle($id, $field);
+ }
+ public function changeAdmin($id) {
+ $field = array(
+ 'name' => 'is_admin',
+ 'type' => 'i',
+ 'value' => !$this->isAdmin($id)
+ );
+ return $this->updateSingle($id, $field);
+ }
public function setUserToken($id) {
$field = array(
diff --git a/public/include/pages/admin/user.inc.php b/public/include/pages/admin/user.inc.php
index 548cdf3a..11808edb 100644
--- a/public/include/pages/admin/user.inc.php
+++ b/public/include/pages/admin/user.inc.php
@@ -11,6 +11,18 @@ if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) {
$aRoundShares = $statistics->getRoundShares();
+// Change account lock
+if ($_POST['do'] == 'lock') {
+ $supress_master = 1;
+ $user->changeLocked($_POST['account_id']);
+}
+
+// Change account admin
+if ($_POST['do'] == 'admin') {
+ $supress_master = 1;
+ $user->changeAdmin($_POST['account_id']);
+}
+
if ($_POST['query']) {
// Fetch requested users
$aUsers = $statistics->getAllUserStats($_POST['query']);
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 1da8c3a4..8cfc263a 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -1,5 +1,22 @@
+
+
{include file="global/block_header.tpl" BLOCK_HEADER="Query User Database"}
-
+
@@ -38,10 +55,14 @@
{$USERS[user].payout.est_payout|number_format:"8"}
{$USERS[user].balance|number_format:"8"}
-
+
+
+
-
+
+
+
{sectionelse}
From 38f2ae5af755bc518e26a7540a624a5d18c04355 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 13:24:46 +0200
Subject: [PATCH 120/168] adding proper avg shares calculation based on target
diff and network diff
---
public/include/smarty_globals.inc.php | 1 +
public/templates/mmcFE/statistics/pool/authenticated.tpl | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index 8ec1e882..d7712942 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -34,6 +34,7 @@ $aGlobal = array(
'blockexplorer' => $config['blockexplorer'],
'chaininfo' => $config['chaininfo'],
'config' => array(
+ 'targetdiff' => $config['difficulty'],
'currency' => $config['currency'],
'txfee' => $config['txfee'],
'payout_system' => $config['payout_system'],
diff --git a/public/templates/mmcFE/statistics/pool/authenticated.tpl b/public/templates/mmcFE/statistics/pool/authenticated.tpl
index 5d21e3eb..bedd8d4b 100644
--- a/public/templates/mmcFE/statistics/pool/authenticated.tpl
+++ b/public/templates/mmcFE/statistics/pool/authenticated.tpl
@@ -33,7 +33,7 @@
- {($ESTTIME * $GLOBAL.sharerate)|number_format:"0"}
+ {(pow(2, 32 - $GLOBAL.config.targetdiff) * $DIFFICULTY)|number_format:"0"}
From ba4a272442c5d5eaf3f18fc2cf116d0e73d920f1 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 13:25:08 +0200
Subject: [PATCH 121/168] reduced row size for time and difficulty
---
public/templates/mmcFE/statistics/blocks/blocks_found.tpl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/public/templates/mmcFE/statistics/blocks/blocks_found.tpl b/public/templates/mmcFE/statistics/blocks/blocks_found.tpl
index 2278fb3c..d66e1349 100644
--- a/public/templates/mmcFE/statistics/blocks/blocks_found.tpl
+++ b/public/templates/mmcFE/statistics/blocks/blocks_found.tpl
@@ -23,8 +23,8 @@
Orphan
{else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if}
{$BLOCKSFOUND[block].finder|default:"unknown"}
- {$BLOCKSFOUND[block].time|date_format:"%d/%m/%Y %H:%M:%S"}
- {$BLOCKSFOUND[block].difficulty|number_format:"8"}
+ {$BLOCKSFOUND[block].time|date_format:"%d/%m %H:%M:%S"}
+ {$BLOCKSFOUND[block].difficulty|number_format:"2"}
{$BLOCKSFOUND[block].shares|number_format}
{/section}
From 01c859d5f51dc580f18a3af257f60b5f886328c7 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 13:25:33 +0200
Subject: [PATCH 122/168] proper number format for USD/Est
---
.../mmcFE/statistics/pool/contributors_hashrate.tpl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
index 67c8f5d7..9086427a 100644
--- a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
+++ b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
@@ -7,7 +7,7 @@
User Name
KH/s
{$GLOBAL.config.currency}/Day
- Usd/Day
+ USD/Day
@@ -20,7 +20,7 @@
{$CONTRIBHASHES[contrib].account}
{$CONTRIBHASHES[contrib].hashrate|number_format}
{$estday|number_format:"3"}
- {$estday|number_format:"3"*$GLOBAL.price|default:"n/a"|number_format:"4"}
+ {($estday * $GLOBAL.price)|default:"n/a"|number_format:"2"}
{/section}
{if $listed != 1}
@@ -29,7 +29,7 @@
{$GLOBAL.userdata.username}
{$GLOBAL.userdata.hashrate}
{$estday|number_format:"3"}
- {$estday|number_format:"3"*$GLOBAL.price|default:"n/a"|number_format:"4"}
+ {($estday * $GLOBAL.price)|default:"n/a"|number_format:"2"}
{/if}
From a703877122e8c89e2888973be66afcc193b40629 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 13:38:32 +0200
Subject: [PATCH 123/168] Adding support do disable account registration
* Adding new configuration variable, see `global.inc.dist.php`
* If you are not able to register anymore check the config var is
* set
Requested in and fixes #150
---
public/include/config/global.inc.dist.php | 1 +
public/include/pages/register.inc.php | 12 ++++++++----
public/include/pages/register/register.inc.php | 9 ++++-----
public/templates/mmcFE/register/disabled.tpl | 3 +++
4 files changed, 16 insertions(+), 9 deletions(-)
create mode 100644 public/templates/mmcFE/register/disabled.tpl
diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php
index e8d12774..4347a513 100644
--- a/public/include/config/global.inc.dist.php
+++ b/public/include/config/global.inc.dist.php
@@ -30,6 +30,7 @@ $config = array(
'max' => 250
),
'website' => array(
+ 'registration' => true, // Allow new users to register
'name' => 'The Pool',
'slogan' => 'Resistance is futile',
'email' => 'test@example.com', // Mail address used for notifications
diff --git a/public/include/pages/register.inc.php b/public/include/pages/register.inc.php
index aecab054..f1c4cb73 100644
--- a/public/include/pages/register.inc.php
+++ b/public/include/pages/register.inc.php
@@ -1,9 +1,13 @@
assign("CONTENT", "default.tpl");
+if (!$config['website']['registration']) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
+ $smarty->assign("CONTENT", "disabled.tpl");
+} else {
+ // Tempalte specifics
+ $smarty->assign("CONTENT", "default.tpl");
+}
?>
diff --git a/public/include/pages/register/register.inc.php b/public/include/pages/register/register.inc.php
index 53e941bf..2e4e4885 100644
--- a/public/include/pages/register/register.inc.php
+++ b/public/include/pages/register/register.inc.php
@@ -1,11 +1,10 @@
register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2'])) {
+if (!$config['website']['registration']) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
+} else if ($user->register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2']) && $config['website']['registration']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'errormsg');
diff --git a/public/templates/mmcFE/register/disabled.tpl b/public/templates/mmcFE/register/disabled.tpl
new file mode 100644
index 00000000..5e5ac8ee
--- /dev/null
+++ b/public/templates/mmcFE/register/disabled.tpl
@@ -0,0 +1,3 @@
+{include file="global/block_header.tpl" BLOCK_HEADER="Registration disabled" BLOCK_STYLE="clear:none;"}
+We are currently not accepting new user registrations.
+{include file="global/block_footer.tpl"}
From 6a5f9388954673d8130a8a3de317639e042017f4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 13:46:32 +0200
Subject: [PATCH 124/168] Store Users IP address in accounts after login
Fixes #177
---
public/include/classes/user.class.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index cc8d7c70..9e69b01d 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -69,7 +69,6 @@ class User {
);
return $this->updateSingle($id, $field);
}
-
public function setUserToken($id) {
$field = array(
'name' => 'token',
@@ -78,6 +77,10 @@ class User {
);
return $this->updateSingle($id, $field);
}
+ private function setUserIp($id, $ip) {
+ $field = array( 'name' => 'loggedIp', 'type' => 's', 'value' => $ip );
+ return $this->updateSingle($id, $field);
+ }
/**
* Fetch all users for administrative tasks
@@ -106,6 +109,7 @@ class User {
}
if ( $this->checkUserPassword($username, $password)) {
$this->createSession($username);
+ $this->setUserIp($this->getUserId($username), $_SERVER['REMOTE_ADDR']);
return true;
}
$this->setErrorMessage("Invalid username or password");
From e681e8abf0c78e2014f8537808878e3e52423c97 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 13:49:53 +0200
Subject: [PATCH 125/168] new full database structure
---
sql/mmcfe_ng_structure.sql | 91 ++++----------------------------------
1 file changed, 9 insertions(+), 82 deletions(-)
diff --git a/sql/mmcfe_ng_structure.sql b/sql/mmcfe_ng_structure.sql
index 1e21bbf4..5d10574f 100644
--- a/sql/mmcfe_ng_structure.sql
+++ b/sql/mmcfe_ng_structure.sql
@@ -1,37 +1,18 @@
--- phpMyAdmin SQL Dump
--- version 3.5.8.1deb1
--- http://www.phpmyadmin.net
---
--- Host: localhost
--- Generation Time: Jun 09, 2013 at 04:08 PM
--- Server version: 5.5.31-0ubuntu0.13.04.1
--- PHP Version: 5.4.9-4ubuntu2
-
-SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
-
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
---
--- Database: `mmcfe_ng`
---
-
--- --------------------------------------------------------
-
---
--- Table structure for table `accounts`
---
-
CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(255) NOT NULL AUTO_INCREMENT,
- `admin` int(1) NOT NULL DEFAULT '0',
+ `is_admin` tinyint(1) NOT NULL DEFAULT '0',
`username` varchar(40) NOT NULL,
`pass` varchar(255) NOT NULL,
`email` varchar(255) DEFAULT NULL COMMENT 'Assocaited email: used for validating users, and re-setting passwords',
+ `is_locked` tinyint(1) NOT NULL DEFAULT '0',
`loggedIp` varchar(255) DEFAULT NULL,
`sessionTimeoutStamp` int(255) DEFAULT NULL,
`pin` varchar(255) NOT NULL COMMENT 'four digit pin to allow account changes',
@@ -44,12 +25,6 @@ CREATE TABLE IF NOT EXISTS `accounts` (
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--- --------------------------------------------------------
-
---
--- Table structure for table `blocks`
---
-
CREATE TABLE IF NOT EXISTS `blocks` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`height` int(10) unsigned NOT NULL,
@@ -65,13 +40,7 @@ CREATE TABLE IF NOT EXISTS `blocks` (
PRIMARY KEY (`id`),
UNIQUE KEY `height` (`height`,`blockhash`),
KEY `time` (`time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Discovered blocks persisted from Litecoin Service';
-
--- --------------------------------------------------------
-
---
--- Table structure for table `notifications`
---
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Discovered blocks persisted from Litecoin Service';
CREATE TABLE IF NOT EXISTS `notifications` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
@@ -84,13 +53,7 @@ CREATE TABLE IF NOT EXISTS `notifications` (
KEY `active` (`active`),
KEY `data` (`data`),
KEY `account_id` (`account_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `notification_settings`
---
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `notification_settings` (
`type` varchar(15) NOT NULL,
@@ -98,12 +61,6 @@ CREATE TABLE IF NOT EXISTS `notification_settings` (
`active` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--- --------------------------------------------------------
-
---
--- Table structure for table `pool_worker`
---
-
CREATE TABLE IF NOT EXISTS `pool_worker` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`account_id` int(255) NOT NULL,
@@ -115,12 +72,6 @@ CREATE TABLE IF NOT EXISTS `pool_worker` (
KEY `account_id` (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--- --------------------------------------------------------
-
---
--- Table structure for table `settings`
---
-
CREATE TABLE IF NOT EXISTS `settings` (
`name` varchar(255) NOT NULL,
`value` varchar(255) DEFAULT NULL,
@@ -128,12 +79,6 @@ CREATE TABLE IF NOT EXISTS `settings` (
UNIQUE KEY `setting` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--- --------------------------------------------------------
-
---
--- Table structure for table `shares`
---
-
CREATE TABLE IF NOT EXISTS `shares` (
`id` bigint(30) NOT NULL AUTO_INCREMENT,
`rem_host` varchar(255) NOT NULL,
@@ -148,13 +93,7 @@ CREATE TABLE IF NOT EXISTS `shares` (
KEY `upstream_result` (`upstream_result`),
KEY `our_result` (`our_result`),
KEY `username` (`username`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `shares_archive`
---
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `shares_archive` (
`id` int(255) unsigned NOT NULL AUTO_INCREMENT,
@@ -167,13 +106,7 @@ CREATE TABLE IF NOT EXISTS `shares_archive` (
PRIMARY KEY (`id`),
UNIQUE KEY `share_id` (`share_id`),
KEY `time` (`time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
-
--- --------------------------------------------------------
-
---
--- Table structure for table `statistics_shares`
---
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
CREATE TABLE IF NOT EXISTS `statistics_shares` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -184,13 +117,7 @@ CREATE TABLE IF NOT EXISTS `statistics_shares` (
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`),
KEY `block_id` (`block_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `transactions`
---
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `transactions` (
`id` int(255) NOT NULL AUTO_INCREMENT,
@@ -204,7 +131,7 @@ CREATE TABLE IF NOT EXISTS `transactions` (
KEY `block_id` (`block_id`),
KEY `account_id` (`account_id`),
KEY `type` (`type`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
From bfaa0a67ef3afdb723a1a2d95bf7534c84f80e11 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 13:59:45 +0200
Subject: [PATCH 126/168] Enforce session logout if IP address changed
Fixes #179
---
public/include/classes/user.class.php | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 9e69b01d..9d747d34 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -44,6 +44,9 @@ class User {
public function getUserToken($id) {
return $this->getSingle($id, 'token', 'id');
}
+ public function getUserIp($id) {
+ return $this->getSingle($id, 'loggedIp', 'id');
+ }
public function getIdFromToken($token) {
return $this->getSingle($token, 'id', 'token', 's');
}
@@ -546,7 +549,7 @@ class User {
**/
public function isAuthenticated() {
$this->debug->append("STA " . __METHOD__, 4);
- if ($_SESSION['AUTHENTICATED'] == true && ! $this->isLocked($_SESSION['USERDATA']['id']))
+ if ($_SESSION['AUTHENTICATED'] == true && ! $this->isLocked($_SESSION['USERDATA']['id']) && $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'])
return true;
// Catchall
$this->logoutUser();
From fac1296812e57f05c50279a924249d3aede04b87 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 14:47:19 +0200
Subject: [PATCH 127/168] adding 3rd party library
---
public/include/recaptchalib.php | 277 ++++++++++++++++++++++++++++++++
1 file changed, 277 insertions(+)
create mode 100644 public/include/recaptchalib.php
diff --git a/public/include/recaptchalib.php b/public/include/recaptchalib.php
new file mode 100644
index 00000000..32c4f4d7
--- /dev/null
+++ b/public/include/recaptchalib.php
@@ -0,0 +1,277 @@
+ $value )
+ $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
+
+ // Cut the last '&'
+ $req=substr($req,0,strlen($req)-1);
+ return $req;
+}
+
+
+
+/**
+ * Submits an HTTP POST to a reCAPTCHA server
+ * @param string $host
+ * @param string $path
+ * @param array $data
+ * @param int port
+ * @return array response
+ */
+function _recaptcha_http_post($host, $path, $data, $port = 80) {
+
+ $req = _recaptcha_qsencode ($data);
+
+ $http_request = "POST $path HTTP/1.0\r\n";
+ $http_request .= "Host: $host\r\n";
+ $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
+ $http_request .= "Content-Length: " . strlen($req) . "\r\n";
+ $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
+ $http_request .= "\r\n";
+ $http_request .= $req;
+
+ $response = '';
+ if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
+ die ('Could not open socket');
+ }
+
+ fwrite($fs, $http_request);
+
+ while ( !feof($fs) )
+ $response .= fgets($fs, 1160); // One TCP-IP packet
+ fclose($fs);
+ $response = explode("\r\n\r\n", $response, 2);
+
+ return $response;
+}
+
+
+
+/**
+ * Gets the challenge HTML (javascript and non-javascript version).
+ * This is called from the browser, and the resulting reCAPTCHA HTML widget
+ * is embedded within the HTML form it was called from.
+ * @param string $pubkey A public key for reCAPTCHA
+ * @param string $error The error given by reCAPTCHA (optional, default is null)
+ * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
+
+ * @return string - The HTML to be embedded in the user's form.
+ */
+function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
+{
+ if ($pubkey == null || $pubkey == '') {
+ die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create ");
+ }
+
+ if ($use_ssl) {
+ $server = RECAPTCHA_API_SECURE_SERVER;
+ } else {
+ $server = RECAPTCHA_API_SERVER;
+ }
+
+ $errorpart = "";
+ if ($error) {
+ $errorpart = "&error=" . $error;
+ }
+ return '
+
+
+
+
+
+ ';
+}
+
+
+
+
+/**
+ * A ReCaptchaResponse is returned from recaptcha_check_answer()
+ */
+class ReCaptchaResponse {
+ var $is_valid;
+ var $error;
+}
+
+
+/**
+ * Calls an HTTP POST function to verify if the user's guess was correct
+ * @param string $privkey
+ * @param string $remoteip
+ * @param string $challenge
+ * @param string $response
+ * @param array $extra_params an array of extra variables to post to the server
+ * @return ReCaptchaResponse
+ */
+function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
+{
+ if ($privkey == null || $privkey == '') {
+ die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create ");
+ }
+
+ if ($remoteip == null || $remoteip == '') {
+ die ("For security reasons, you must pass the remote ip to reCAPTCHA");
+ }
+
+
+
+ //discard spam submissions
+ if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
+ $recaptcha_response = new ReCaptchaResponse();
+ $recaptcha_response->is_valid = false;
+ $recaptcha_response->error = 'incorrect-captcha-sol';
+ return $recaptcha_response;
+ }
+
+ $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
+ array (
+ 'privatekey' => $privkey,
+ 'remoteip' => $remoteip,
+ 'challenge' => $challenge,
+ 'response' => $response
+ ) + $extra_params
+ );
+
+ $answers = explode ("\n", $response [1]);
+ $recaptcha_response = new ReCaptchaResponse();
+
+ if (trim ($answers [0]) == 'true') {
+ $recaptcha_response->is_valid = true;
+ }
+ else {
+ $recaptcha_response->is_valid = false;
+ $recaptcha_response->error = $answers [1];
+ }
+ return $recaptcha_response;
+
+}
+
+/**
+ * gets a URL where the user can sign up for reCAPTCHA. If your application
+ * has a configuration page where you enter a key, you should provide a link
+ * using this function.
+ * @param string $domain The domain where the page is hosted
+ * @param string $appname The name of your application
+ */
+function recaptcha_get_signup_url ($domain = null, $appname = null) {
+ return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
+}
+
+function _recaptcha_aes_pad($val) {
+ $block_size = 16;
+ $numpad = $block_size - (strlen ($val) % $block_size);
+ return str_pad($val, strlen ($val) + $numpad, chr($numpad));
+}
+
+/* Mailhide related code */
+
+function _recaptcha_aes_encrypt($val,$ky) {
+ if (! function_exists ("mcrypt_encrypt")) {
+ die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
+ }
+ $mode=MCRYPT_MODE_CBC;
+ $enc=MCRYPT_RIJNDAEL_128;
+ $val=_recaptcha_aes_pad($val);
+ return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
+}
+
+
+function _recaptcha_mailhide_urlbase64 ($x) {
+ return strtr(base64_encode ($x), '+/', '-_');
+}
+
+/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
+function recaptcha_mailhide_url($pubkey, $privkey, $email) {
+ if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
+ die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
+ "you can do so at http://www.google.com/recaptcha/mailhide/apikey ");
+ }
+
+
+ $ky = pack('H*', $privkey);
+ $cryptmail = _recaptcha_aes_encrypt ($email, $ky);
+
+ return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
+}
+
+/**
+ * gets the parts of the email to expose to the user.
+ * eg, given johndoe@example,com return ["john", "example.com"].
+ * the email is then displayed as john...@example.com
+ */
+function _recaptcha_mailhide_email_parts ($email) {
+ $arr = preg_split("/@/", $email );
+
+ if (strlen ($arr[0]) <= 4) {
+ $arr[0] = substr ($arr[0], 0, 1);
+ } else if (strlen ($arr[0]) <= 6) {
+ $arr[0] = substr ($arr[0], 0, 3);
+ } else {
+ $arr[0] = substr ($arr[0], 0, 4);
+ }
+ return $arr;
+}
+
+/**
+ * Gets html to display an email address given a public an private key.
+ * to get a key, go to:
+ *
+ * http://www.google.com/recaptcha/mailhide/apikey
+ */
+function recaptcha_mailhide_html($pubkey, $privkey, $email) {
+ $emailparts = _recaptcha_mailhide_email_parts ($email);
+ $url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
+
+ return htmlentities($emailparts[0]) . "... @" . htmlentities ($emailparts [1]);
+
+}
+
+
+?>
From dda1585353dd9c50319a85147a1761c946280fc6 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 14:47:33 +0200
Subject: [PATCH 128/168] Adding ReCaptcha support for account registration
* You will need to create a re-captcha account for your site
* Disabled by default to keep backwards compatability
Fixes #179
---
public/include/config/global.inc.dist.php | 6 +++
public/include/pages/register.inc.php | 4 ++
.../include/pages/register/register.inc.php | 43 ++++++++++++++++---
public/templates/mmcFE/register/default.tpl | 19 ++++----
4 files changed, 59 insertions(+), 13 deletions(-)
diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php
index 4347a513..b41d9110 100644
--- a/public/include/config/global.inc.dist.php
+++ b/public/include/config/global.inc.dist.php
@@ -35,6 +35,12 @@ $config = array(
'slogan' => 'Resistance is futile',
'email' => 'test@example.com', // Mail address used for notifications
),
+ // See: http://www.google.com/recaptcha
+ 'recaptcha' => array(
+ 'enabled' => false, // Enable re-captcha during registraion
+ 'public_key' => 'YOUR_PUBLIC_RECAPTCHA_KEY',
+ 'private_key' => 'YOUR_PRIVATE_RECAPTCHA_KEY'
+ ),
'currency' => 'LTC', // Currency name to be used on website
'txfee' => 0.1, // Default tx fee added by RPC server
'block_bonus' => 0,
diff --git a/public/include/pages/register.inc.php b/public/include/pages/register.inc.php
index f1c4cb73..d0a1d713 100644
--- a/public/include/pages/register.inc.php
+++ b/public/include/pages/register.inc.php
@@ -7,6 +7,10 @@ if (!$config['website']['registration']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
$smarty->assign("CONTENT", "disabled.tpl");
} else {
+ if ($config['recaptcha']['enabled']) {
+ require_once(INCLUDE_DIR . '/recaptchalib.php');
+ $smarty->assign("RECAPTCHA", recaptcha_get_html($config['recaptcha']['public_key']));
+ }
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
}
diff --git a/public/include/pages/register/register.inc.php b/public/include/pages/register/register.inc.php
index 2e4e4885..ce41630e 100644
--- a/public/include/pages/register/register.inc.php
+++ b/public/include/pages/register/register.inc.php
@@ -2,12 +2,45 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
-if (!$config['website']['registration']) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
-} else if ($user->register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2']) && $config['website']['registration']) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login');
+if ($config['recaptcha']['enabled']) {
+ // Load re-captcha specific data
+ require_once(INCLUDE_DIR . '/recaptchalib.php');
+ $rsp = recaptcha_check_answer (
+ $config['recaptcha']['private_key'],
+ $_SERVER["REMOTE_ADDR"],
+ $_POST["recaptcha_challenge_field"],
+ $_POST["recaptcha_response_field"]
+ );
+}
+
+// Check if recaptcha is enabled, process form data if valid
+if($config['recaptcha']['enabled'] && $_POST["recaptcha_response_field"] && $_POST["recaptcha_response_field"]!=''){
+ if ($rsp->is_valid) {
+ $smarty->assign("RECAPTCHA", recaptcha_get_html($config['recaptcha']['public_key']));
+ if (!$config['website']['registration']) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
+ } else if ($user->register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2']) && $config['website']['registration']) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'errormsg');
+ }
+ } else {
+ $smarty->assign("RECAPTCHA", recaptcha_get_html($config['recaptcha']['public_key'], $rsp->error));
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again. (' . $rsp->error . ')', 'TYPE' => 'errormsg');
+ }
+// Empty captcha
+} else if ($config['recaptcha']['enabled']) {
+ $smarty->assign("RECAPTCHA", recaptcha_get_html($config['recaptcha']['public_key'], $rsp->error));
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Empty Captcha, please try again.', 'TYPE' => 'errormsg');
+// Captcha disabled
} else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'errormsg');
+ if (!$config['website']['registration']) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
+ } else if ($user->register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2']) && $config['website']['registration']) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'errormsg');
+ }
}
// We load the default registration template instead of an action specific one
diff --git a/public/templates/mmcFE/register/default.tpl b/public/templates/mmcFE/register/default.tpl
index d4440f1c..f711c67f 100644
--- a/public/templates/mmcFE/register/default.tpl
+++ b/public/templates/mmcFE/register/default.tpl
@@ -3,13 +3,16 @@
-
+
+ Username:
+ Password:
+ Repeat Password:
+ Email:
+ Email Repeat:
+ PIN: (4 digit number. Remember this pin! )
+ {nocache}{$RECAPTCHA}{/nocache}
+
+
+
{include file="global/block_footer.tpl"}
From 5d356b5c4ff383c26e213a494f034f2057dbbdad Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 15:26:23 +0200
Subject: [PATCH 129/168] Adding counter for failed login attempts
* Track failed login attempts of a user
* Reset failed attempts as soon as the login succeeded
Fixes #182
---
public/include/classes/user.class.php | 35 +++++++++++++++------------
sql/issue_182_accounts_upgrade.sql | 1 +
2 files changed, 20 insertions(+), 16 deletions(-)
create mode 100644 sql/issue_182_accounts_upgrade.sql
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 9d747d34..20ff072d 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -47,6 +47,9 @@ class User {
public function getUserIp($id) {
return $this->getSingle($id, 'loggedIp', 'id');
}
+ public function getUserFailed($id) {
+ return $this->getSingle($id, 'failed_logins', 'id');
+ }
public function getIdFromToken($token) {
return $this->getSingle($token, 'id', 'token', 's');
}
@@ -57,27 +60,23 @@ class User {
return $this->getUserAdmin($id);
}
public function changeLocked($id) {
- $field = array(
- 'name' => 'is_locked',
- 'type' => 'i',
- 'value' => !$this->isLocked($id)
- );
+ $field = array('name' => 'is_locked', 'type' => 'i', 'value' => !$this->isLocked($id));
return $this->updateSingle($id, $field);
}
public function changeAdmin($id) {
- $field = array(
- 'name' => 'is_admin',
- 'type' => 'i',
- 'value' => !$this->isAdmin($id)
- );
+ $field = array('name' => 'is_admin', 'type' => 'i', 'value' => !$this->isAdmin($id));
return $this->updateSingle($id, $field);
}
public function setUserToken($id) {
- $field = array(
- 'name' => 'token',
- 'type' => 's',
- 'value' => hash('sha256', $id.time().$this->salt)
- );
+ $field = array('name' => 'token', 'type' => 's', 'value' => hash('sha256', $id.time().$this->salt));
+ return $this->updateSingle($id, $field);
+ }
+ private function setUserFailed($id, $value) {
+ $field = array( 'name' => 'failed_logins', 'type' => 'i', 'value' => $value);
+ return $this->updateSingle($id, $field);
+ }
+ private function incUserFailed($id) {
+ $field = array( 'name' => 'failed_logins', 'type' => 'i', 'value' => $this->getUserFailed($id) + 1);
return $this->updateSingle($id, $field);
}
private function setUserIp($id, $ip) {
@@ -112,10 +111,14 @@ class User {
}
if ( $this->checkUserPassword($username, $password)) {
$this->createSession($username);
+ $this->setUserFailed($this->getUserId($username), 0);
$this->setUserIp($this->getUserId($username), $_SERVER['REMOTE_ADDR']);
return true;
}
$this->setErrorMessage("Invalid username or password");
+ if ($id = $this->getUserId($username))
+ $this->incUserFailed($id);
+
return false;
}
@@ -213,7 +216,7 @@ class User {
**/
private function updateSingle($id, $field) {
$this->debug->append("STA " . __METHOD__, 4);
- $stmt = $this->mysqli->prepare("UPDATE $this->table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1");
+ $stmt = $this->mysqli->prepare("UPDATE $this->table SET `" . $field['name'] . "` = ? WHERE id = ? LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute())
return true;
$this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id");
diff --git a/sql/issue_182_accounts_upgrade.sql b/sql/issue_182_accounts_upgrade.sql
new file mode 100644
index 00000000..62266515
--- /dev/null
+++ b/sql/issue_182_accounts_upgrade.sql
@@ -0,0 +1 @@
+ALTER TABLE `accounts` ADD `failed_logins` INT( 5 ) UNSIGNED NULL DEFAULT '0' AFTER `is_locked` ;
From a912819192dcbaf252fa69a4822cdcf31c43f7c1 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 16:38:48 +0300
Subject: [PATCH 130/168] Update README.md
* Added re-captcha reference
* Added new donor
---
README.md | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 33551e74..c7e8998a 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ Donors
These people have supported this project with a donation:
* [obigal](https://github.com/obigal)
+* [vias](https://github.com/vias79)
Requirements
============
@@ -57,10 +58,11 @@ The following feature have been implemented so far:
* Reward Systems
* Propotional
- * PPS **NEW**
+ * PPS
* (Planned) PPLNS
* Use of memcache for statistics instead of a cronjob
* Web User accounts
+ * Re-Captcha protected registration form
* Worker accounts
* Worker activity (live, past 10 minutes)
* Worker hashrates (live, past 10 minutes)
@@ -68,8 +70,8 @@ The following feature have been implemented so far:
* Minimal Block statistics
* Pool donations
* Pool fees
-* Manual payout with 0.1 LTC fee
-* Auto payout with 0.1 LTC fee
+* Manual payout
+* Auto payout
* Transaction list (confirmed and unconfirmed)
* Admin Panel
* User Listing including statistics
@@ -80,7 +82,7 @@ The following feature have been implemented so far:
* IDLE Workers
* New blocks found in pool
* Auto Payout
- * Manual Payou
+ * Manual Payout
Installation
============
From acc4880dd695c1b73701fecf86d846bac0639094 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 16:25:52 +0200
Subject: [PATCH 131/168] Adding block luck graph
* Added expected vs actual share graph to block stats
* Added new small table template for overall stats in pool stats
Fixes #91
---
.../include/pages/statistics/blocks.inc.php | 2 +-
.../mmcFE/statistics/blocks/default.tpl | 70 +++++++++++++++++++
.../{blocks_found.tpl => small_table.tpl} | 13 +---
.../mmcFE/statistics/pool/authenticated.tpl | 2 +-
4 files changed, 74 insertions(+), 13 deletions(-)
create mode 100644 public/templates/mmcFE/statistics/blocks/default.tpl
rename public/templates/mmcFE/statistics/blocks/{blocks_found.tpl => small_table.tpl} (62%)
diff --git a/public/include/pages/statistics/blocks.inc.php b/public/include/pages/statistics/blocks.inc.php
index 69bbade7..e83aa8a8 100644
--- a/public/include/pages/statistics/blocks.inc.php
+++ b/public/include/pages/statistics/blocks.inc.php
@@ -13,5 +13,5 @@ $aBlockData = $aBlocksFoundData[0];
$smarty->assign("BLOCKSFOUND", $aBlocksFoundData);
$smarty->assign("BLOCKLIMIT", $iLimit);
-$smarty->assign("CONTENT", "blocks_found.tpl");
+$smarty->assign("CONTENT", "default.tpl");
?>
diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl
new file mode 100644
index 00000000..1511a46b
--- /dev/null
+++ b/public/templates/mmcFE/statistics/blocks/default.tpl
@@ -0,0 +1,70 @@
+{include file="global/block_header.tpl" BLOCK_HEADER="Block Luck" BLOCK_STYLE="clear:none;"}
+
+
+
+{section block $BLOCKSFOUND}
+ {$BLOCKSFOUND[block].height}
+{/section}
+
+
+
+
+ Expected Shares
+{section block $BLOCKSFOUND}
+ {(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)}
+{/section}
+
+
+ Actual Shares
+{section block $BLOCKSFOUND}
+ {$BLOCKSFOUND[block].shares}
+{/section}
+
+
+
+
+
+The graph above illustrates N shares to find a block vs. E Shares expected to find a block based on
+target and network difficulty and assuming a zero variance scenario.
+
+{include file="global/block_footer.tpl"}
+
+{include file="global/block_header.tpl" BLOCK_HEADER="Last $BLOCKLIMIT Blocks Found" BLOCK_STYLE="clear:none;"}
+
+
+
+
+ Block
+ Validity
+ Finder
+ Time
+ Difficulty
+ Expected Shares
+ Actual Shares
+
+
+
+{assign var=rank value=1}
+{section block $BLOCKSFOUND}
+
+ {$BLOCKSFOUND[block].height}
+
+ {if $BLOCKSFOUND[block].confirmations >= $GLOBAL.confirmations}
+ Confirmed
+ {else if $BLOCKSFOUND[block].confirmations == -1}
+ Orphan
+ {else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if}
+ {$BLOCKSFOUND[block].finder|default:"unknown"}
+ {$BLOCKSFOUND[block].time|date_format:"%d/%m %H:%M:%S"}
+ {$BLOCKSFOUND[block].difficulty|number_format:"2"}
+ {(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)|number_format}
+ {$BLOCKSFOUND[block].shares|number_format}
+
+{/section}
+
+
+
+
+ Note: Round Earnings are not credited until {$GLOBAL.confirmations} confirms.
+
+{include file="global/block_footer.tpl"}
diff --git a/public/templates/mmcFE/statistics/blocks/blocks_found.tpl b/public/templates/mmcFE/statistics/blocks/small_table.tpl
similarity index 62%
rename from public/templates/mmcFE/statistics/blocks/blocks_found.tpl
rename to public/templates/mmcFE/statistics/blocks/small_table.tpl
index d66e1349..9152fcc7 100644
--- a/public/templates/mmcFE/statistics/blocks/blocks_found.tpl
+++ b/public/templates/mmcFE/statistics/blocks/small_table.tpl
@@ -1,14 +1,12 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Last $BLOCKLIMIT Blocks Found" BLOCK_STYLE="clear:none;"}
-
+
Block
- Validity
Finder
Time
- Difficulty
- Shares
+ Actual Shares
@@ -16,15 +14,8 @@
{section block $BLOCKSFOUND}
{$BLOCKSFOUND[block].height}
-
- {if $BLOCKSFOUND[block].confirmations >= $GLOBAL.confirmations}
- Confirmed
- {else if $BLOCKSFOUND[block].confirmations == -1}
- Orphan
- {else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if}
{$BLOCKSFOUND[block].finder|default:"unknown"}
{$BLOCKSFOUND[block].time|date_format:"%d/%m %H:%M:%S"}
- {$BLOCKSFOUND[block].difficulty|number_format:"2"}
{$BLOCKSFOUND[block].shares|number_format}
{/section}
diff --git a/public/templates/mmcFE/statistics/pool/authenticated.tpl b/public/templates/mmcFE/statistics/pool/authenticated.tpl
index bedd8d4b..5c67bbcd 100644
--- a/public/templates/mmcFE/statistics/pool/authenticated.tpl
+++ b/public/templates/mmcFE/statistics/pool/authenticated.tpl
@@ -44,6 +44,6 @@
{include file="global/block_footer.tpl"}
-{include file="statistics/blocks/blocks_found.tpl" ALIGN="right"}
+{include file="statistics/blocks/small_table.tpl" ALIGN="right" SHORT=true}
{include file="global/block_footer.tpl"}
From cc046a286cb04f4ab6cd37a1326e3cb37c396d33 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 16:34:04 +0200
Subject: [PATCH 132/168] fixing missing transactions table
---
public/include/pages/account/transactions.inc.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/include/pages/account/transactions.inc.php b/public/include/pages/account/transactions.inc.php
index f6bdbfb2..db927ca7 100644
--- a/public/include/pages/account/transactions.inc.php
+++ b/public/include/pages/account/transactions.inc.php
@@ -2,7 +2,7 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
-if (!$user->isAuthenticated()) {
+if ($user->isAuthenticated()) {
$aTransactions = $transaction->getTransactions($_SESSION['USERDATA']['id']);
if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'errormsg');
$smarty->assign('TRANSACTIONS', $aTransactions);
From 88b9d95ff26aa13184c71492e188261487669b05 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 16:41:38 +0200
Subject: [PATCH 133/168] Only run some globals for smarty if loggedin
* Do not check for round shares if user is not logged in
* Will prevent a long page load for new users trying to register
* Only needed on statistics page that is not available to guests
---
public/include/smarty_globals.inc.php | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index d7712942..257d33d4 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -7,16 +7,19 @@ if (!defined('SECURITY'))
// Globally available variables
$debug->append('Global smarty variables', 3);
+// Only run these if the user is logged in
+if ($_SESSION['AUTHENTICATED']) {
+ $aRoundShares = $statistics->getRoundShares();
+ if ($bitcoin->can_connect() === true){
+ $dDifficulty = $bitcoin->query('getdifficulty');
+ } else {
+ $dDifficulty = 1;
+ }
+}
// Fetch some data
-$aRoundShares = $statistics->getRoundShares();
$iCurrentActiveWorkers = $worker->getCountAllActiveWorkers();
$iCurrentPoolHashrate = $statistics->getCurrentHashrate();
$iCurrentPoolShareRate = $statistics->getCurrentShareRate();
-if ($bitcoin->can_connect() === true){
- $dDifficulty = $bitcoin->query('getdifficulty');
-} else {
- $dDifficulty = 1;
-}
// Global data for Smarty
$aGlobal = array(
From 538c5ead8808975904e08369ad15d7a4d93ef5a8 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 17:09:59 +0200
Subject: [PATCH 134/168] properly sort blocks in graph
---
public/templates/mmcFE/statistics/blocks/default.tpl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl
index 1511a46b..0cfec471 100644
--- a/public/templates/mmcFE/statistics/blocks/default.tpl
+++ b/public/templates/mmcFE/statistics/blocks/default.tpl
@@ -2,7 +2,7 @@
-{section block $BLOCKSFOUND}
+{section block $BLOCKSFOUND step=-1}
{$BLOCKSFOUND[block].height}
{/section}
@@ -10,13 +10,13 @@
Expected Shares
-{section block $BLOCKSFOUND}
+{section block $BLOCKSFOUND step=-1}
{(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)}
{/section}
Actual Shares
-{section block $BLOCKSFOUND}
+{section block $BLOCKSFOUND step=-1}
{$BLOCKSFOUND[block].shares}
{/section}
From d9886d8dca3be3bbf0f57b0b32438eccf684269f Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 22:00:28 +0200
Subject: [PATCH 135/168] re-adding tooltips for graphs
---
.../mmcFE/js/jquery.tooltip.visualize.js | 106 ++
.../site_assets/mmcFE/js/jquery.visualize.js | 1601 ++++++++---------
2 files changed, 901 insertions(+), 806 deletions(-)
create mode 100644 public/site_assets/mmcFE/js/jquery.tooltip.visualize.js
diff --git a/public/site_assets/mmcFE/js/jquery.tooltip.visualize.js b/public/site_assets/mmcFE/js/jquery.tooltip.visualize.js
new file mode 100644
index 00000000..f6f71fd9
--- /dev/null
+++ b/public/site_assets/mmcFE/js/jquery.tooltip.visualize.js
@@ -0,0 +1,106 @@
+/**
+ * --------------------------------------------------------------------
+ * Tooltip plugin for the jQuery-Plugin "Visualize"
+ * Tolltip by Iraê Carvalho, irae@irae.pro.br, http://irae.pro.br/en/
+ * Copyright (c) 2010 Iraê Carvalho
+ * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
+ *
+ * Visualize plugin by Scott Jehl, scott@filamentgroup.com
+ * Copyright (c) 2009 Filament Group, http://www.filamentgroup.com
+ *
+ * --------------------------------------------------------------------
+ */
+
+(function($){
+ $.visualizePlugins.push(function visualizeTooltip(options,tableData) {
+ //configuration
+ var o = $.extend({
+ tooltip: false,
+ tooltipalign: 'auto', // also available 'left' and 'right'
+ tooltipvalign: 'top',
+ tooltipclass: 'visualize-tooltip',
+ tooltiphtml: function(data){
+ if(options.multiHover) {
+ var html='';
+ for(var i=0;i'+data.point[i].value+' - '+data.point[i].yLabels[0]+'';
+ }
+ return html;
+ } else {
+ return ''+data.point.value+' - '+data.point.yLabels[0]+'
';
+ }
+ },
+ delay:false
+ },options);
+
+ // don't go any further if we are not to show anything
+ if(!o.tooltip) {return;}
+
+ var self = $(this),
+ canvasContain = self.next(),
+ scroller = canvasContain.find('.visualize-scroller'),
+ scrollerW = scroller.width(),
+ tracker = canvasContain.find('.visualize-interaction-tracker');
+
+ // IE needs background color and opacity white or the tracker stays behind the tooltip
+ tracker.css({
+ backgroundColor:'white',
+ opacity:0,
+ zIndex:100
+ });
+
+ var tooltip = $('
').css({
+ position:'absolute',
+ display:'none',
+ zIndex:90
+ })
+ .insertAfter(scroller.find('canvas'));
+
+ var usescroll = true;
+
+ if( typeof(G_vmlCanvasManager) != 'undefined' ){
+ scroller.css({'position':'absolute'});
+ tracker.css({marginTop:'-'+(o.height)+'px'});
+ }
+
+
+ self.bind('vizualizeOver',function visualizeTooltipOver(e,data){
+ if(data.canvasContain.get(0) != canvasContain.get(0)) {return;} // for multiple graphs originated from same table
+ if(o.multiHover) {
+ var p = data.point[0].canvasCords;
+ } else {
+ var p = data.point.canvasCords;
+ }
+ var left,right,top,clasRem,clasAd,bottom,x=Math.round(p[0]+data.tableData.zeroLocX),y=Math.round(p[1]+data.tableData.zeroLocY);
+ if(o.tooltipalign == 'left' || ( o.tooltipalign=='auto' && x-scroller.scrollLeft()<=scrollerW/2 ) ) {
+ if($.browser.msie && ($.browser.version == 7 || $.browser.version == 6) ) {usescroll=false;} else {usescroll=true;}
+ left = (x-(usescroll?scroller.scrollLeft():0))+'px';
+ right = '';
+ clasAdd="tooltipleft";
+ clasRem="tooltipright";
+ } else {
+ if($.browser.msie && $.browser.version == 7) {usescroll=false;} else {usescroll=true;}
+ left = '';
+ right = (Math.abs(x-o.width)- (o.width-(usescroll?scroller.scrollLeft():0)-scrollerW) )+'px';
+ clasAdd="tooltipright";
+ clasRem="tooltipleft";
+ }
+
+ tooltip
+ .addClass(clasAdd)
+ .removeClass(clasRem)
+ .html(o.tooltiphtml(data))
+ .css({
+ display:'block',
+ top: y+'px',
+ left: left,
+ right: right
+ });
+ });
+
+ self.bind('vizualizeOut',function visualizeTooltipOut(e,data){
+ tooltip.css({display:'none'});
+ });
+
+ });
+})(jQuery);
\ No newline at end of file
diff --git a/public/site_assets/mmcFE/js/jquery.visualize.js b/public/site_assets/mmcFE/js/jquery.visualize.js
index 3daf800a..1043aaca 100644
--- a/public/site_assets/mmcFE/js/jquery.visualize.js
+++ b/public/site_assets/mmcFE/js/jquery.visualize.js
@@ -1,806 +1,795 @@
-/**
- * --------------------------------------------------------------------
- * jQuery-Plugin "visualize"
- * by Scott Jehl, scott@filamentgroup.com
- * http://www.filamentgroup.com
- * Copyright (c) 2009 Filament Group
- * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
- *
- * --------------------------------------------------------------------
- */
-(function ($) {
- $.fn.visualize = function (options, container) {
- return $(this).each(function () {
- //configuration
- var o = $.extend({
- type: 'bar',
- //also available: area, pie, line
- width: $(this).width(),
- //height of canvas - defaults to table height
- height: $(this).height(),
- //height of canvas - defaults to table height
- appendTitle: true,
- //table caption text is added to chart
- title: null,
- //grabs from table caption if null
- appendKey: true,
- //color key is added to chart
- colors: ['#be1e2d', '#666699', '#92d5ea', '#ee8310', '#8d10ee', '#5a3b16', '#26a4ed', '#f45a90', '#e9e744'],
- textColors: [],
- //corresponds with colors array. null/undefined items will fall back to CSS
- parseDirection: 'x',
- //which direction to parse the table data
- pieMargin: 10,
- //pie charts only - spacing around pie
- pieLabelsAsPercent: true,
- pieLabelPos: 'inside',
- lineWeight: 4,
- //for line and area - stroke weight
- lineDots: false,
- //also available: 'single', 'double'
- dotInnerColor: "#ffffff",
- // only used for lineDots:'double'
- lineMargin: (options.lineDots ? 15 : 0),
- //for line and area - spacing around lines
- barGroupMargin: 10,
- chartId: '',
- xLabelParser: null,
- // function to parse labels as values
- valueParser: null,
- // function to parse values. must return a Number
- chartId: '',
- chartClass: '',
- barMargin: 1,
- //space around bars in bar chart (added to both sides of bar)
- yLabelInterval: 30,
- //distance between y labels
- interaction: false // only used for lineDots != false -- triggers mouseover and mouseout on original table
- }, options);
-
- //reset width, height to numbers
- o.width = parseFloat(o.width);
- o.height = parseFloat(o.height);
-
- // reset padding if graph is not lines
- if (o.type != 'line' && o.type != 'area') {
- o.lineMargin = 0;
- }
-
- var self = $(this);
-
- // scrape data from html table
- var tableData = {};
- var colors = o.colors;
- var textColors = o.textColors;
-
-
- var parseLabels = function (direction) {
- var labels = [];
- if (direction == 'x') {
- self.find('thead tr').each(function (i) {
- $(this).find('th').each(function (j) {
- if (!labels[j]) {
- labels[j] = [];
- }
- labels[j][i] = $(this).text()
- })
- });
- } else {
- self.find('tbody tr').each(function (i) {
- $(this).find('th').each(function (j) {
- if (!labels[i]) {
- labels[i] = [];
- }
- labels[i][j] = $(this).text()
- });
- });
- }
- return labels;
- };
-
- var fnParse = o.valueParser || parseFloat;
- var dataGroups = tableData.dataGroups = [];
- if (o.parseDirection == 'x') {
- self.find('tbody tr').each(function (i, tr) {
- dataGroups[i] = {};
- dataGroups[i].points = [];
- dataGroups[i].color = colors[i];
- if (textColors[i]) {
- dataGroups[i].textColor = textColors[i];
- }
- $(tr).find('td').each(function (j, td) {
- dataGroups[i].points.push({
- value: fnParse($(td).text()),
- elem: td,
- tableCords: [i, j]
- });
- });
- });
- } else {
- var cols = self.find('tbody tr:eq(0) td').size();
- for (var i = 0; i < cols; i++) {
- dataGroups[i] = {};
- dataGroups[i].points = [];
- dataGroups[i].color = colors[i];
- if (textColors[i]) {
- dataGroups[i].textColor = textColors[i];
- }
- self.find('tbody tr').each(function (j) {
- dataGroups[i].points.push({
- value: $(this).find('td').eq(i).text() * 1,
- elem: this,
- tableCords: [i, j]
- });
- });
- };
- }
-
-
- var allItems = tableData.allItems = [];
- $(dataGroups).each(function (i, row) {
- var count = 0;
- $.each(row.points, function (j, point) {
- allItems.push(point);
- count += point.value;
- });
- row.groupTotal = count;
- });
-
- tableData.dataSum = 0;
- tableData.topValue = 0;
- tableData.bottomValue = Infinity;
- $.each(allItems, function (i, item) {
- tableData.dataSum += fnParse(item.value);
- if (fnParse(item.value, 10) > tableData.topValue) {
- tableData.topValue = fnParse(item.value, 10);
- }
- if (item.value < tableData.bottomValue) {
- tableData.bottomValue = fnParse(item.value);
- }
- });
- var dataSum = tableData.dataSum;
- var topValue = tableData.topValue;
- var bottomValue = tableData.bottomValue;
-
- var xAllLabels = tableData.xAllLabels = parseLabels(o.parseDirection);
- var yAllLabels = tableData.yAllLabels = parseLabels(o.parseDirection === 'x' ? 'y' : 'x');
-
- var xLabels = tableData.xLabels = [];
- $.each(tableData.xAllLabels, function (i, labels) {
- tableData.xLabels.push(labels[0]);
- });
-
- var totalYRange = tableData.totalYRange = tableData.topValue - tableData.bottomValue;
-
- var zeroLocX = tableData.zeroLocX = 0;
-
- if ($.isFunction(o.xLabelParser)) {
-
- var xTopValue = null;
- var xBottomValue = null;
-
- $.each(xLabels, function (i, label) {
- label = xLabels[i] = o.xLabelParser(label);
- if (i === 0) {
- xTopValue = label;
- xBottomValue = label;
- }
- if (label > xTopValue) {
- xTopValue = label;
- }
- if (label < xBottomValue) {
- xBottomValue = label;
- }
- });
-
- var totalXRange = tableData.totalXRange = xTopValue - xBottomValue;
-
-
- var xScale = tableData.xScale = (o.width - 2 * o.lineMargin) / totalXRange;
- var marginDiffX = 0;
- if (o.lineMargin) {
- var marginDiffX = -2 * xScale - o.lineMargin;
- }
- zeroLocX = tableData.zeroLocX = xBottomValue + o.lineMargin;
-
- tableData.xBottomValue = xBottomValue;
- tableData.xTopValue = xTopValue;
- tableData.totalXRange = totalXRange;
- }
-
- var yScale = tableData.yScale = (o.height - 2 * o.lineMargin) / totalYRange;
- var zeroLocY = tableData.zeroLocY = (o.height - 2 * o.lineMargin) * (tableData.topValue / tableData.totalYRange) + o.lineMargin;
-
- var yLabels = tableData.yLabels = [];
-
- var numLabels = Math.floor((o.height - 2 * o.lineMargin) / 30);
-
- var loopInterval = tableData.totalYRange / numLabels; //fix provided from lab
- loopInterval = Math.round(parseFloat(loopInterval) / 5) * 5;
- loopInterval = Math.max(loopInterval, 1);
-
- // var start =
- for (var j = Math.round(parseInt(tableData.bottomValue) / 5) * 5; j <= tableData.topValue - loopInterval; j += loopInterval) {
- yLabels.push(j);
- }
- if (yLabels[yLabels.length - 1] > tableData.topValue + loopInterval) {
- yLabels.pop();
- } else if (yLabels[yLabels.length - 1] <= tableData.topValue - 10) {
- yLabels.push(tableData.topValue);
- }
-
- // populate some data
- $.each(dataGroups, function (i, row) {
- row.yLabels = tableData.yAllLabels[i];
- $.each(row.points, function (j, point) {
- point.zeroLocY = tableData.zeroLocY;
- point.zeroLocX = tableData.zeroLocX;
- point.xLabels = tableData.xAllLabels[j];
- point.yLabels = tableData.yAllLabels[i];
- point.color = row.color;
- });
- });
-
- try {
- console.log(tableData);
- } catch (e) {}
-
- var charts = {};
-
- charts.pie = {
- interactionPoints: dataGroups,
-
- setup: function () {
- charts.pie.draw(true);
- },
- draw: function (drawHtml) {
-
- var centerx = Math.round(canvas.width() / 2);
- var centery = Math.round(canvas.height() / 2);
- var radius = centery - o.pieMargin;
- var counter = 0.0;
-
- if (drawHtml) {
- canvasContain.addClass('visualize-pie');
-
- if (o.pieLabelPos == 'outside') {
- canvasContain.addClass('visualize-pie-outside');
- }
-
- var toRad = function (integer) {
- return (Math.PI / 180) * integer;
- };
- var labels = $('').insertAfter(canvas);
- }
-
-
- //draw the pie pieces
- $.each(dataGroups, function (i, row) {
- var fraction = row.groupTotal / dataSum;
- if (fraction <= 0 || isNaN(fraction)) return;
- ctx.beginPath();
- ctx.moveTo(centerx, centery);
- ctx.arc(centerx, centery, radius, counter * Math.PI * 2 - Math.PI * 0.5, (counter + fraction) * Math.PI * 2 - Math.PI * 0.5, false);
- ctx.lineTo(centerx, centery);
- ctx.closePath();
- ctx.fillStyle = dataGroups[i].color;
- ctx.fill();
- // draw labels
- if (drawHtml) {
- var sliceMiddle = (counter + fraction / 2);
- var distance = o.pieLabelPos == 'inside' ? radius / 1.5 : radius + radius / 5;
- var labelx = Math.round(centerx + Math.sin(sliceMiddle * Math.PI * 2) * (distance));
- var labely = Math.round(centery - Math.cos(sliceMiddle * Math.PI * 2) * (distance));
- var leftRight = (labelx > centerx) ? 'right' : 'left';
- var topBottom = (labely > centery) ? 'bottom' : 'top';
- var percentage = parseFloat((fraction * 100).toFixed(2));
-
- // interaction variables
- row.canvasCords = [labelx, labely];
- row.zeroLocY = tableData.zeroLocY = 0; // related to zeroLocY and plugin API
- row.zeroLocX = tableData.zeroLocX = 0; // related to zeroLocX and plugin API
- row.value = row.groupTotal;
-
-
- if (percentage) {
- var labelval = (o.pieLabelsAsPercent) ? percentage + '%' : row.groupTotal;
- var labeltext = $('' + labelval + ' ').css(leftRight, 0).css(topBottom, 0);
- if (labeltext) var label = $(' ').appendTo(labels).css({
- left: labelx,
- top: labely
- }).append(labeltext);
- labeltext.css('font-size', radius / 8).css('margin-' + leftRight, -labeltext.width() / 2).css('margin-' + topBottom, -labeltext.outerHeight() / 2);
-
- if (dataGroups[i].textColor) {
- labeltext.css('color', dataGroups[i].textColor);
- }
-
- }
- }
- counter += fraction;
- });
- }
- };
-
- (function () {
-
- var xInterval;
-
- var drawPoint = function (ctx, x, y, color, size) {
- ctx.moveTo(x, y);
- ctx.beginPath();
- ctx.arc(x, y, size / 2, 0, 2 * Math.PI, false);
- ctx.closePath();
- ctx.fillStyle = color;
- ctx.fill();
- };
-
- charts.line = {
-
- interactionPoints: allItems,
-
- setup: function (area) {
-
- if (area) {
- canvasContain.addClass('visualize-area');
- } else {
- canvasContain.addClass('visualize-line');
- }
-
- //write X labels
- var xlabelsUL = $('').width(canvas.width()).height(canvas.height()).insertBefore(canvas);
-
- if (!o.customXLabels) {
- xInterval = (canvas.width() - 2 * o.lineMargin) / (xLabels.length - 1);
- $.each(xLabels, function (i) {
- var thisLi = $('' + this + ' ').prepend(' ').css('left', o.lineMargin + xInterval * i).appendTo(xlabelsUL);
- var label = thisLi.find('span:not(.line)');
- var leftOffset = label.width() / -2;
- if (i == 0) {
- leftOffset = -20;
- } else if (i == xLabels.length - 1) {
- leftOffset = -label.width() + 20;
- }
- label.css('margin-left', leftOffset).addClass('label');
- });
- } else {
- o.customXLabels(tableData, xlabelsUL);
- }
-
- //write Y labels
- var liBottom = (canvas.height() - 2 * o.lineMargin) / (yLabels.length - 1);
- var ylabelsUL = $('').width(canvas.width()).height(canvas.height())
- // .css('margin-top',-o.lineMargin)
- .insertBefore(scroller);
-
- $.each(yLabels, function (i) {
- var value = Math.floor(this);
- var posB = (value - bottomValue) * yScale + o.lineMargin;
- if (posB >= o.height - 1 || posB < 0) {
- return;
- }
- var thisLi = $('' + value + ' ').css('bottom', posB);
- if (Math.abs(posB) < o.height - 1) {
- thisLi.prepend(' ');
- }
- thisLi.prependTo(ylabelsUL);
-
- var label = thisLi.find('span:not(.line)');
- var topOffset = label.height() / -2;
- if (!o.lineMargin) {
- if (i == 0) {
- topOffset = -label.height();
- } else if (i == yLabels.length - 1) {
- topOffset = 0;
- }
- }
- label.css('margin-top', topOffset).addClass('label');
- });
-
- //start from the bottom left
- ctx.translate(zeroLocX, zeroLocY);
-
- charts.line.draw(area);
-
- },
-
- draw: function (area) {
- // prevent drawing on top of previous draw
- ctx.clearRect(-zeroLocX, -zeroLocY, o.width, o.height);
- // Calculate each point properties before hand
- var integer;
- $.each(dataGroups, function (i, row) {
- integer = o.lineMargin; // the current offset
- $.each(row.points, function (j, point) {
- if (o.xLabelParser) {
- point.canvasCords = [(xLabels[j] - zeroLocX) * xScale - xBottomValue, -(point.value * yScale)];
- } else {
- point.canvasCords = [integer, -(point.value * yScale)];
- }
-
- if (o.lineDots) {
- point.dotSize = o.dotSize || o.lineWeight * Math.PI;
- point.dotInnerSize = o.dotInnerSize || o.lineWeight * Math.PI / 2;
- if (o.lineDots == 'double') {
- point.innerColor = o.dotInnerColor;
- }
- }
- integer += xInterval;
- });
- });
- // fire custom event so we can enable rich interaction
- self.trigger('vizualizeBeforeDraw', {
- options: o,
- table: self,
- canvasContain: canvasContain,
- tableData: tableData
- });
- // draw lines and areas
- $.each(dataGroups, function (h) {
- // Draw lines
- ctx.beginPath();
- ctx.lineWidth = o.lineWeight;
- ctx.lineJoin = 'round';
- $.each(this.points, function (g) {
- var loc = this.canvasCords;
- if (g == 0) {
- ctx.moveTo(loc[0], loc[1]);
- }
- ctx.lineTo(loc[0], loc[1]);
- });
- ctx.strokeStyle = this.color;
- ctx.stroke();
- // Draw fills
- if (area) {
- var integer = this.points[this.points.length - 1].canvasCords[0];
- if (isFinite(integer)) ctx.lineTo(integer, 0);
- ctx.lineTo(o.lineMargin, 0);
- ctx.closePath();
- ctx.fillStyle = this.color;
- ctx.globalAlpha = .3;
- ctx.fill();
- ctx.globalAlpha = 1.0;
- } else {
- ctx.closePath();
- }
- });
- // draw points
- if (o.lineDots) {
- $.each(dataGroups, function (h) {
- $.each(this.points, function (g) {
- drawPoint(ctx, this.canvasCords[0], this.canvasCords[1], this.color, this.dotSize);
- if (o.lineDots === 'double') {
- drawPoint(ctx, this.canvasCords[0], this.canvasCords[1], this.innerColor, this.dotInnerSize);
- }
- });
- });
- }
-
- }
- };
-
- })();
-
- charts.area = {
- setup: function () {
- charts.line.setup(true);
- },
- draw: charts.line.draw
- };
-
- (function () {
-
- var horizontal, bottomLabels;
-
- charts.bar = {
- setup: function () {
- /**
- * We can draw horizontal or vertical bars depending on the
- * value of the 'barDirection' option (which may be 'vertical' or
- * 'horizontal').
- */
-
- horizontal = (o.barDirection == 'horizontal');
-
- canvasContain.addClass('visualize-bar');
-
- /**
- * Write labels along the bottom of the chart. If we're drawing
- * horizontal bars, these will be the yLabels, otherwise they
- * will be the xLabels. The positioning also varies slightly:
- * yLabels are values, hence they will span the whole width of
- * the canvas, whereas xLabels are supposed to line up with the
- * bars.
- */
- bottomLabels = horizontal ? yLabels : xLabels;
-
- var xInterval = canvas.width() / (bottomLabels.length - (horizontal ? 1 : 0));
-
- var xlabelsUL = $('').width(canvas.width()).height(canvas.height()).insertBefore(canvas);
-
- $.each(bottomLabels, function (i) {
- var thisLi = $('' + this + ' ').prepend(' ').css('left', xInterval * i).width(xInterval).appendTo(xlabelsUL);
-
- if (horizontal) {
- var label = thisLi.find('span.label');
- label.css("margin-left", -label.width() / 2);
- }
- });
-
- /**
- * Write labels along the left of the chart. Follows the same idea
- * as the bottom labels.
- */
- var leftLabels = horizontal ? xLabels : yLabels;
- var liBottom = canvas.height() / (leftLabels.length - (horizontal ? 0 : 1));
-
- var ylabelsUL = $('').width(canvas.width()).height(canvas.height()).insertBefore(canvas);
-
- $.each(leftLabels, function (i) {
- var thisLi = $('' + this + ' ').prependTo(ylabelsUL);
-
- var label = thisLi.find('span:not(.line)').addClass('label');
-
- if (horizontal) {
- /**
- * For left labels, we want to vertically align the text
- * to the middle of its container, but we don't know how
- * many lines of text we will have, since the labels could
- * be very long.
- *
- * So we set a min-height of liBottom, and a max-height
- * of liBottom + 1, so we can then check the label's actual
- * height to determine if it spans one line or more lines.
- */
- label.css({
- 'min-height': liBottom,
- 'max-height': liBottom + 1,
- 'vertical-align': 'middle'
- });
- thisLi.css({
- 'top': liBottom * i,
- 'min-height': liBottom
- });
-
- var r = label[0].getClientRects()[0];
- if (r.bottom - r.top == liBottom) {
-/* This means we have only one line of text; hence
- * we can centre the text vertically by setting the line-height,
- * as described at:
- * http://www.ampsoft.net/webdesign-l/vertical-aligned-nav-list.html
- *
- * (Although firefox has .height on the rectangle, IE doesn't,
- * so we use r.bottom - r.top rather than r.height.)
- */
- label.css('line-height', parseInt(liBottom) + 'px');
- } else {
-/*
- * If there is more than one line of text, then we shouldn't
- * touch the line height, but we should make sure the text
- * doesn't overflow the container.
- */
- label.css("overflow", "hidden");
- }
- } else {
- thisLi.css('bottom', liBottom * i).prepend(' ');
- label.css('margin-top', -label.height() / 2)
- }
- });
-
- charts.bar.draw();
-
- },
-
- draw: function () {
- // Draw bars
- if (horizontal) {
- // for horizontal, keep the same code, but rotate everything 90 degrees
- // clockwise.
- ctx.rotate(Math.PI / 2);
- } else {
- // for vertical, translate to the top left corner.
- ctx.translate(0, zeroLocY);
- }
-
- // Don't attempt to draw anything if all the values are zero,
- // otherwise we will get weird exceptions from the canvas methods.
- if (totalYRange <= 0) return;
-
- var yScale = (horizontal ? canvas.width() : canvas.height()) / totalYRange;
- var barWidth = horizontal ? (canvas.height() / xLabels.length) : (canvas.width() / (bottomLabels.length));
- var linewidth = (barWidth - o.barGroupMargin * 2) / dataGroups.length;
-
- for (var h = 0; h < dataGroups.length; h++) {
- ctx.beginPath();
-
- var strokeWidth = linewidth - (o.barMargin * 2);
- ctx.lineWidth = strokeWidth;
- var points = dataGroups[h].points;
- var integer = 0;
- for (var i = 0; i < points.length; i++) {
- // If the last value is zero, IE will go nuts and not draw anything,
- // so don't try to draw zero values at all.
- if (points[i].value != 0) {
- var xVal = (integer - o.barGroupMargin) + (h * linewidth) + linewidth / 2;
- xVal += o.barGroupMargin * 2;
- ctx.moveTo(xVal, 0);
- ctx.lineTo(xVal, Math.round(-points[i].value * yScale));
- }
- integer += barWidth;
- }
- ctx.strokeStyle = dataGroups[h].color;
- ctx.stroke();
- ctx.closePath();
- }
-
- }
- };
-
- })();
-
- //create new canvas, set w&h attrs (not inline styles)
- var canvasNode = document.createElement("canvas");
- var canvas = $(canvasNode).attr({
- 'height': o.height,
- 'width': o.width
- });
-
- //get title for chart
- var title = o.title || self.find('caption').text();
-
- //create canvas wrapper div, set inline w&h, append
- var canvasContain = (container || $('
')).height(o.height).width(o.width);
-
- var scroller = $('
').appendTo(canvasContain).append(canvas);
-
- //title/key container
- if (o.appendTitle || o.appendKey) {
- var infoContain = $('
').appendTo(canvasContain);
- }
-
- //append title
- if (o.appendTitle) {
- $('' + title + '
').appendTo(infoContain);
- }
-
-
- //append key
- if (o.appendKey) {
- var newKey = $('');
- $.each(yAllLabels, function (i, label) {
- $('' + label + ' ').appendTo(newKey);
- });
- newKey.appendTo(infoContain);
- };
-
- // init interaction
- if (o.interaction) {
- // sets the canvas to track interaction
- // IE needs one div on top of the canvas since the VML shapes prevent mousemove from triggering correctly.
- // Pie charts needs tracker because labels goes on top of the canvas and also messes up with mousemove
- var tracker = $('
').css({
- 'height': o.height + 'px',
- 'width': o.width + 'px',
- 'position': 'relative',
- 'z-index': 200
- }).insertAfter(canvas);
-
- var triggerInteraction = function (overOut, data) {
- var data = $.extend({
- canvasContain: canvasContain,
- tableData: tableData
- }, data);
- self.trigger('vizualize' + overOut, data);
- };
-
- var over = false,
- last = false,
- started = false;
- tracker.mousemove(function (e) {
- var x, y, x1, y1, data, dist, i, current, selector, zLabel, elem, color, minDist, found, ev = e.originalEvent;
-
- // get mouse position relative to the tracker/canvas
- x = ev.layerX || ev.offsetX || 0;
- y = ev.layerY || ev.offsetY || 0;
-
- found = false;
- minDist = started ? 30000 : (o.type == 'pie' ? (Math.round(canvas.height() / 2) - o.pieMargin) / 3 : o.lineWeight * 4);
- // iterate datagroups to find points with matching
- $.each(charts[o.type].interactionPoints, function (i, current) {
- x1 = current.canvasCords[0] + zeroLocX;
- y1 = current.canvasCords[1] + (o.type == "pie" ? 0 : zeroLocY);
- dist = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
- if (dist < minDist) {
- found = current;
- minDist = dist;
- }
- });
-
- if (o.multiHover && found) {
- x = found.canvasCords[0] + zeroLocX;
- y = found.canvasCords[1] + (o.type == "pie" ? 0 : zeroLocY);
- found = [found];
- $.each(charts[o.type].interactionPoints, function (i, current) {
- if (current == found[0]) {
- return;
- }
- x1 = current.canvasCords[0] + zeroLocX;
- y1 = current.canvasCords[1] + zeroLocY;
- dist = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
- if (dist <= o.multiHover) {
- found.push(current);
- }
- });
- }
- // trigger over and out only when state changes, instead of on every mousemove
- over = found;
- if (over != last) {
- if (over) {
- if (last) {
- triggerInteraction('Out', {
- point: last
- });
- }
- triggerInteraction('Over', {
- point: over
- });
- last = over;
- }
- if (last && !over) {
- triggerInteraction('Out', {
- point: last
- });
- last = false;
- }
- started = true;
- }
- });
- tracker.mouseleave(function () {
- triggerInteraction('Out', {
- point: last,
- mouseOutGraph: true
- });
- over = (last = false);
- });
- }
-
- //append new canvas to page
- if (!container) {
- canvasContain.insertAfter(this);
- }
- if (typeof (G_vmlCanvasManager) != 'undefined') {
- G_vmlCanvasManager.init();
- G_vmlCanvasManager.initElement(canvas[0]);
- }
-
- //set up the drawing board
- var ctx = canvas[0].getContext('2d');
-
- // Scroll graphs
- scroller.scrollLeft(o.width - scroller.width());
-
- // init plugins
- $.each($.visualizePlugins, function (i, plugin) {
- plugin.call(self, o, tableData);
- });
-
- //create chart
- charts[o.type].setup();
-
- if (!container) {
- //add event for updating
- self.bind('visualizeRefresh', function () {
- self.visualize(o, $(this).empty());
- });
- //add event for redraw
- self.bind('visualizeRedraw', function () {
- charts[o.type].draw();
- });
- }
- }).next(); //returns canvas(es)
- };
- // create array for plugins. if you wish to make a plugin,
- // just push your init funcion into this array
- $.visualizePlugins = [];
-
-})(jQuery);
+/**
+ * --------------------------------------------------------------------
+ * jQuery-Plugin "visualize"
+ * by Scott Jehl, scott@filamentgroup.com
+ * http://www.filamentgroup.com
+ * Copyright (c) 2009 Filament Group
+ * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
+ *
+ * --------------------------------------------------------------------
+ */
+(function($) {
+$.fn.visualize = function(options, container){
+ return $(this).each(function(){
+ //configuration
+ var o = $.extend({
+ type: 'bar', //also available: area, pie, line
+ width: $(this).width(), //height of canvas - defaults to table height
+ height: $(this).height(), //height of canvas - defaults to table height
+ appendTitle: true, //table caption text is added to chart
+ title: null, //grabs from table caption if null
+ appendKey: true, //color key is added to chart
+ colors: ['#be1e2d','#666699','#92d5ea','#ee8310','#8d10ee','#5a3b16','#26a4ed','#f45a90','#e9e744'],
+ textColors: [], //corresponds with colors array. null/undefined items will fall back to CSS
+ parseDirection: 'x', //which direction to parse the table data
+ pieMargin: 10, //pie charts only - spacing around pie
+ pieLabelsAsPercent: true,
+ pieLabelPos: 'inside',
+ lineWeight: 4, //for line and area - stroke weight
+ lineDots: false, //also available: 'single', 'double'
+ dotInnerColor: "#ffffff", // only used for lineDots:'double'
+ lineMargin: (options.lineDots?15:0), //for line and area - spacing around lines
+ barGroupMargin: 10,
+ chartId: '',
+ xLabelParser: null, // function to parse labels as values
+ valueParser: null, // function to parse values. must return a Number
+ chartId: '',
+ chartClass: '',
+ barMargin: 1, //space around bars in bar chart (added to both sides of bar)
+ yLabelInterval: 30, //distance between y labels
+ interaction: false // only used for lineDots != false -- triggers mouseover and mouseout on original table
+ },options);
+
+ //reset width, height to numbers
+ o.width = parseFloat(o.width);
+ o.height = parseFloat(o.height);
+
+ // reset padding if graph is not lines
+ if(o.type != 'line' && o.type != 'area' ) {
+ o.lineMargin = 0;
+ }
+
+ var self = $(this);
+
+ // scrape data from html table
+ var tableData = {};
+ var colors = o.colors;
+ var textColors = o.textColors;
+
+
+ var parseLabels = function(direction){
+ var labels = [];
+ if(direction == 'x'){
+ self.find('thead tr').each(function(i){
+ $(this).find('th').each(function(j){
+ if(!labels[j]) {
+ labels[j] = [];
+ }
+ labels[j][i] = $(this).text()
+ })
+ });
+ }
+ else {
+ self.find('tbody tr').each(function(i){
+ $(this).find('th').each(function(j) {
+ if(!labels[i]) {
+ labels[i] = [];
+ }
+ labels[i][j] = $(this).text()
+ });
+ });
+ }
+ return labels;
+ };
+
+ var fnParse = o.valueParser || parseFloat;
+ var dataGroups = tableData.dataGroups = [];
+ if(o.parseDirection == 'x'){
+ self.find('tbody tr').each(function(i,tr){
+ dataGroups[i] = {};
+ dataGroups[i].points = [];
+ dataGroups[i].color = colors[i];
+ if(textColors[i]){ dataGroups[i].textColor = textColors[i]; }
+ $(tr).find('td').each(function(j,td){
+ dataGroups[i].points.push( {
+ value: fnParse($(td).text()),
+ elem: td,
+ tableCords: [i,j]
+ } );
+ });
+ });
+ } else {
+ var cols = self.find('tbody tr:eq(0) td').size();
+ for(var i=0; itableData.topValue) {
+ tableData.topValue = fnParse(item.value,10);
+ }
+ if(item.valuexTopValue) {
+ xTopValue = label;
+ }
+ if(label tableData.topValue+loopInterval) {
+ yLabels.pop();
+ } else if (yLabels[yLabels.length-1] <= tableData.topValue-10) {
+ yLabels.push(tableData.topValue);
+ }
+
+ // populate some data
+ $.each(dataGroups,function(i,row){
+ row.yLabels = tableData.yAllLabels[i];
+ $.each(row.points, function(j,point){
+ point.zeroLocY = tableData.zeroLocY;
+ point.zeroLocX = tableData.zeroLocX;
+ point.xLabels = tableData.xAllLabels[j];
+ point.yLabels = tableData.yAllLabels[i];
+ point.color = row.color;
+ });
+ });
+
+ try{console.log(tableData);}catch(e){}
+
+ var charts = {};
+
+ charts.pie = {
+ interactionPoints: dataGroups,
+
+ setup: function() {
+ charts.pie.draw(true);
+ },
+ draw: function(drawHtml){
+
+ var centerx = Math.round(canvas.width()/2);
+ var centery = Math.round(canvas.height()/2);
+ var radius = centery - o.pieMargin;
+ var counter = 0.0;
+
+ if(drawHtml) {
+ canvasContain.addClass('visualize-pie');
+
+ if(o.pieLabelPos == 'outside'){ canvasContain.addClass('visualize-pie-outside'); }
+
+ var toRad = function(integer){ return (Math.PI/180)*integer; };
+ var labels = $('')
+ .insertAfter(canvas);
+ }
+
+
+ //draw the pie pieces
+ $.each(dataGroups, function(i,row){
+ var fraction = row.groupTotal / dataSum;
+ if (fraction <= 0 || isNaN(fraction))
+ return;
+ ctx.beginPath();
+ ctx.moveTo(centerx, centery);
+ ctx.arc(centerx, centery, radius,
+ counter * Math.PI * 2 - Math.PI * 0.5,
+ (counter + fraction) * Math.PI * 2 - Math.PI * 0.5,
+ false);
+ ctx.lineTo(centerx, centery);
+ ctx.closePath();
+ ctx.fillStyle = dataGroups[i].color;
+ ctx.fill();
+ // draw labels
+ if(drawHtml) {
+ var sliceMiddle = (counter + fraction/2);
+ var distance = o.pieLabelPos == 'inside' ? radius/1.5 : radius + radius / 5;
+ var labelx = Math.round(centerx + Math.sin(sliceMiddle * Math.PI * 2) * (distance));
+ var labely = Math.round(centery - Math.cos(sliceMiddle * Math.PI * 2) * (distance));
+ var leftRight = (labelx > centerx) ? 'right' : 'left';
+ var topBottom = (labely > centery) ? 'bottom' : 'top';
+ var percentage = parseFloat((fraction*100).toFixed(2));
+
+ // interaction variables
+ row.canvasCords = [labelx,labely];
+ row.zeroLocY = tableData.zeroLocY = 0; // related to zeroLocY and plugin API
+ row.zeroLocX = tableData.zeroLocX = 0; // related to zeroLocX and plugin API
+ row.value = row.groupTotal;
+
+
+ if(percentage){
+ var labelval = (o.pieLabelsAsPercent) ? percentage + '%' : row.groupTotal;
+ var labeltext = $('' + labelval +' ')
+ .css(leftRight, 0)
+ .css(topBottom, 0);
+ if(labeltext)
+ var label = $(' ')
+ .appendTo(labels)
+ .css({left: labelx, top: labely})
+ .append(labeltext);
+ labeltext
+ .css('font-size', radius / 8)
+ .css('margin-'+leftRight, -labeltext.width()/2)
+ .css('margin-'+topBottom, -labeltext.outerHeight()/2);
+
+ if(dataGroups[i].textColor){ labeltext.css('color', dataGroups[i].textColor); }
+
+ }
+ }
+ counter+=fraction;
+ });
+ }
+ };
+
+ (function(){
+
+ var xInterval;
+
+ var drawPoint = function (ctx,x,y,color,size) {
+ ctx.moveTo(x,y);
+ ctx.beginPath();
+ ctx.arc(x,y,size/2,0,2*Math.PI,false);
+ ctx.closePath();
+ ctx.fillStyle = color;
+ ctx.fill();
+ };
+
+ charts.line = {
+
+ interactionPoints: allItems,
+
+ setup: function(area){
+
+ if(area){ canvasContain.addClass('visualize-area'); }
+ else{ canvasContain.addClass('visualize-line'); }
+
+ //write X labels
+ var xlabelsUL = $('')
+ .width(canvas.width())
+ .height(canvas.height())
+ .insertBefore(canvas);
+
+ if(!o.customXLabels) {
+ xInterval = (canvas.width() - 2*o.lineMargin) / (xLabels.length -1);
+ $.each(xLabels, function(i){
+ var thisLi = $(''+this+' ')
+ .prepend(' ')
+ .css('left', o.lineMargin + xInterval * i)
+ .appendTo(xlabelsUL);
+ var label = thisLi.find('span:not(.line)');
+ var leftOffset = label.width()/-2;
+ if(i == 0){ leftOffset = 0; }
+ else if(i== xLabels.length-1){ leftOffset = -label.width(); }
+ label
+ .css('margin-left', leftOffset)
+ .addClass('label');
+ });
+ } else {
+ o.customXLabels(tableData,xlabelsUL);
+ }
+
+ //write Y labels
+ var liBottom = (canvas.height() - 2*o.lineMargin) / (yLabels.length-1);
+ var ylabelsUL = $('')
+ .width(canvas.width())
+ .height(canvas.height())
+ // .css('margin-top',-o.lineMargin)
+ .insertBefore(scroller);
+
+ $.each(yLabels, function(i){
+ var value = Math.floor(this);
+ var posB = (value-bottomValue)*yScale + o.lineMargin;
+ if(posB >= o.height-1 || posB < 0) {
+ return;
+ }
+ var thisLi = $(''+value+' ')
+ .css('bottom', posB);
+ if(Math.abs(posB) < o.height-1) {
+ thisLi.prepend(' ');
+ }
+ thisLi.prependTo(ylabelsUL);
+
+ var label = thisLi.find('span:not(.line)');
+ var topOffset = label.height()/-2;
+ if(!o.lineMargin) {
+ if(i == 0){ topOffset = -label.height(); }
+ else if(i== yLabels.length-1){ topOffset = 0; }
+ }
+ label
+ .css('margin-top', topOffset)
+ .addClass('label');
+ });
+
+ //start from the bottom left
+ ctx.translate(zeroLocX,zeroLocY);
+
+ charts.line.draw(area);
+
+ },
+
+ draw: function(area) {
+ // prevent drawing on top of previous draw
+ ctx.clearRect(-zeroLocX,-zeroLocY,o.width,o.height);
+ // Calculate each point properties before hand
+ var integer;
+ $.each(dataGroups,function(i,row){
+ integer = o.lineMargin; // the current offset
+ $.each(row.points, function(j,point){
+ if(o.xLabelParser) {
+ point.canvasCords = [(xLabels[j]-zeroLocX)*xScale - xBottomValue,-(point.value*yScale)];
+ } else {
+ point.canvasCords = [integer,-(point.value*yScale)];
+ }
+
+ if(o.lineDots) {
+ point.dotSize = o.dotSize||o.lineWeight*Math.PI;
+ point.dotInnerSize = o.dotInnerSize||o.lineWeight*Math.PI/2;
+ if(o.lineDots == 'double') {
+ point.innerColor = o.dotInnerColor;
+ }
+ }
+ integer+=xInterval;
+ });
+ });
+ // fire custom event so we can enable rich interaction
+ self.trigger('vizualizeBeforeDraw',{options:o,table:self,canvasContain:canvasContain,tableData:tableData});
+ // draw lines and areas
+ $.each(dataGroups,function(h){
+ // Draw lines
+ ctx.beginPath();
+ ctx.lineWidth = o.lineWeight;
+ ctx.lineJoin = 'round';
+ $.each(this.points, function(g){
+ var loc = this.canvasCords;
+ if(g == 0) {
+ ctx.moveTo(loc[0],loc[1]);
+ }
+ ctx.lineTo(loc[0],loc[1]);
+ });
+ ctx.strokeStyle = this.color;
+ ctx.stroke();
+ // Draw fills
+ if(area){
+ var integer = this.points[this.points.length-1].canvasCords[0];
+ if (isFinite(integer))
+ ctx.lineTo(integer,0);
+ ctx.lineTo(o.lineMargin,0);
+ ctx.closePath();
+ ctx.fillStyle = this.color;
+ ctx.globalAlpha = .3;
+ ctx.fill();
+ ctx.globalAlpha = 1.0;
+ }
+ else {ctx.closePath();}
+ });
+ // draw points
+ if(o.lineDots) {
+ $.each(dataGroups,function(h){
+ $.each(this.points, function(g){
+ drawPoint(ctx,this.canvasCords[0],this.canvasCords[1],this.color,this.dotSize);
+ if(o.lineDots === 'double') {
+ drawPoint(ctx,this.canvasCords[0],this.canvasCords[1],this.innerColor,this.dotInnerSize);
+ }
+ });
+ });
+ }
+
+ }
+ };
+
+ })();
+
+ charts.area = {
+ setup: function() {
+ charts.line.setup(true);
+ },
+ draw: charts.line.draw
+ };
+
+ (function(){
+
+ var horizontal,bottomLabels;
+
+ charts.bar = {
+ setup:function(){
+ /**
+ * We can draw horizontal or vertical bars depending on the
+ * value of the 'barDirection' option (which may be 'vertical' or
+ * 'horizontal').
+ */
+
+ horizontal = (o.barDirection == 'horizontal');
+
+ canvasContain.addClass('visualize-bar');
+
+ /**
+ * Write labels along the bottom of the chart. If we're drawing
+ * horizontal bars, these will be the yLabels, otherwise they
+ * will be the xLabels. The positioning also varies slightly:
+ * yLabels are values, hence they will span the whole width of
+ * the canvas, whereas xLabels are supposed to line up with the
+ * bars.
+ */
+ bottomLabels = horizontal ? yLabels : xLabels;
+
+ var xInterval = canvas.width() / (bottomLabels.length - (horizontal ? 1 : 0));
+
+ var xlabelsUL = $('')
+ .width(canvas.width())
+ .height(canvas.height())
+ .insertBefore(canvas);
+
+ $.each(bottomLabels, function(i){
+ var thisLi = $(''+this+' ')
+ .prepend(' ')
+ .css('left', xInterval * i)
+ .width(xInterval)
+ .appendTo(xlabelsUL);
+
+ if (horizontal) {
+ var label = thisLi.find('span.label');
+ label.css("margin-left", -label.width() / 2);
+ }
+ });
+
+ /**
+ * Write labels along the left of the chart. Follows the same idea
+ * as the bottom labels.
+ */
+ var leftLabels = horizontal ? xLabels : yLabels;
+ var liBottom = canvas.height() / (leftLabels.length - (horizontal ? 0 : 1));
+
+ var ylabelsUL = $('')
+ .width(canvas.width())
+ .height(canvas.height())
+ .insertBefore(canvas);
+
+ $.each(leftLabels, function(i){
+ var thisLi = $(''+this+' ').prependTo(ylabelsUL);
+
+ var label = thisLi.find('span:not(.line)').addClass('label');
+
+ if (horizontal) {
+ /**
+ * For left labels, we want to vertically align the text
+ * to the middle of its container, but we don't know how
+ * many lines of text we will have, since the labels could
+ * be very long.
+ *
+ * So we set a min-height of liBottom, and a max-height
+ * of liBottom + 1, so we can then check the label's actual
+ * height to determine if it spans one line or more lines.
+ */
+ label.css({
+ 'min-height': liBottom,
+ 'max-height': liBottom + 1,
+ 'vertical-align': 'middle'
+ });
+ thisLi.css({'top': liBottom * i, 'min-height': liBottom});
+
+ var r = label[0].getClientRects()[0];
+ if (r.bottom - r.top == liBottom) {
+ /* This means we have only one line of text; hence
+ * we can centre the text vertically by setting the line-height,
+ * as described at:
+ * http://www.ampsoft.net/webdesign-l/vertical-aligned-nav-list.html
+ *
+ * (Although firefox has .height on the rectangle, IE doesn't,
+ * so we use r.bottom - r.top rather than r.height.)
+ */
+ label.css('line-height', parseInt(liBottom) + 'px');
+ }
+ else {
+ /*
+ * If there is more than one line of text, then we shouldn't
+ * touch the line height, but we should make sure the text
+ * doesn't overflow the container.
+ */
+ label.css("overflow", "hidden");
+ }
+ }
+ else {
+ thisLi.css('bottom', liBottom * i).prepend(' ');
+ label.css('margin-top', -label.height() / 2)
+ }
+ });
+
+ charts.bar.draw();
+
+ },
+
+ draw: function() {
+ // Draw bars
+
+ if (horizontal) {
+ // for horizontal, keep the same code, but rotate everything 90 degrees
+ // clockwise.
+ ctx.rotate(Math.PI / 2);
+ }
+ else {
+ // for vertical, translate to the top left corner.
+ ctx.translate(0, zeroLocY);
+ }
+
+ // Don't attempt to draw anything if all the values are zero,
+ // otherwise we will get weird exceptions from the canvas methods.
+ if (totalYRange <= 0)
+ return;
+
+ var yScale = (horizontal ? canvas.width() : canvas.height()) / totalYRange;
+ var barWidth = horizontal ? (canvas.height() / xLabels.length) : (canvas.width() / (bottomLabels.length));
+ var linewidth = (barWidth - o.barGroupMargin*2) / dataGroups.length;
+
+ for(var h=0; h '))
+ .height(o.height)
+ .width(o.width);
+
+ var scroller = $('
')
+ .appendTo(canvasContain)
+ .append(canvas);
+
+ //title/key container
+ if(o.appendTitle || o.appendKey){
+ var infoContain = $('
')
+ .appendTo(canvasContain);
+ }
+
+ //append title
+ if(o.appendTitle){
+ $(''+ title +'
').appendTo(infoContain);
+ }
+
+
+ //append key
+ if(o.appendKey){
+ var newKey = $('');
+ $.each(yAllLabels, function(i,label){
+ $(''+ label +' ')
+ .appendTo(newKey);
+ });
+ newKey.appendTo(infoContain);
+ };
+
+ // init interaction
+ if(o.interaction) {
+ // sets the canvas to track interaction
+ // IE needs one div on top of the canvas since the VML shapes prevent mousemove from triggering correctly.
+ // Pie charts needs tracker because labels goes on top of the canvas and also messes up with mousemove
+ var tracker = $('
')
+ .css({
+ 'height': o.height + 'px',
+ 'width': o.width + 'px',
+ 'position':'relative',
+ 'z-index': 200
+ })
+ .insertAfter(canvas);
+
+ var triggerInteraction = function(overOut,data) {
+ var data = $.extend({
+ canvasContain:canvasContain,
+ tableData:tableData
+ },data);
+ self.trigger('vizualize'+overOut,data);
+ };
+
+ var over=false, last=false, started=false;
+ tracker.mousemove(function(e){
+ var x,y,x1,y1,data,dist,i,current,selector,zLabel,elem,color,minDist,found,ev=e.originalEvent;
+
+ // get mouse position relative to the tracker/canvas
+ x = ev.layerX || ev.offsetX || 0;
+ y = ev.layerY || ev.offsetY || 0;
+
+ found = false;
+ minDist = started?30000:(o.type=='pie'?(Math.round(canvas.height()/2)-o.pieMargin)/3:o.lineWeight*4);
+ // iterate datagroups to find points with matching
+ $.each(charts[o.type].interactionPoints,function(i,current){
+ x1 = current.canvasCords[0] + zeroLocX;
+ y1 = current.canvasCords[1] + (o.type=="pie"?0:zeroLocY);
+ dist = Math.sqrt( (x1 - x)*(x1 - x) + (y1 - y)*(y1 - y) );
+ if(dist < minDist) {
+ found = current;
+ minDist = dist;
+ }
+ });
+
+ if(o.multiHover && found) {
+ x = found.canvasCords[0] + zeroLocX;
+ y = found.canvasCords[1] + (o.type=="pie"?0:zeroLocY);
+ found = [found];
+ $.each(charts[o.type].interactionPoints,function(i,current){
+ if(current == found[0]) {return;}
+ x1 = current.canvasCords[0] + zeroLocX;
+ y1 = current.canvasCords[1] + zeroLocY;
+ dist = Math.sqrt( (x1 - x)*(x1 - x) + (y1 - y)*(y1 - y) );
+ if(dist <= o.multiHover) {
+ found.push(current);
+ }
+ });
+ }
+ // trigger over and out only when state changes, instead of on every mousemove
+ over = found;
+ if(over != last) {
+ if(over) {
+ if(last) {
+ triggerInteraction('Out',{point:last});
+ }
+ triggerInteraction('Over',{point:over});
+ last = over;
+ }
+ if(last && !over) {
+ triggerInteraction('Out',{point:last});
+ last=false;
+ }
+ started=true;
+ }
+ });
+ tracker.mouseleave(function(){
+ triggerInteraction('Out',{
+ point:last,
+ mouseOutGraph:true
+ });
+ over = (last = false);
+ });
+ }
+
+ //append new canvas to page
+ if(!container){canvasContain.insertAfter(this); }
+ if( typeof(G_vmlCanvasManager) != 'undefined' ){ G_vmlCanvasManager.init(); G_vmlCanvasManager.initElement(canvas[0]); }
+
+ //set up the drawing board
+ var ctx = canvas[0].getContext('2d');
+
+ // Scroll graphs
+ scroller.scrollLeft(o.width-scroller.width());
+
+ // init plugins
+ $.each($.visualizePlugins,function(i,plugin){
+ plugin.call(self,o,tableData);
+ });
+
+ //create chart
+ charts[o.type].setup();
+
+ if(!container){
+ //add event for updating
+ self.bind('visualizeRefresh', function(){
+ self.visualize(o, $(this).empty());
+ });
+ //add event for redraw
+ self.bind('visualizeRedraw', function(){
+ charts[o.type].draw();
+ });
+ }
+ }).next(); //returns canvas(es)
+};
+// create array for plugins. if you wish to make a plugin,
+// just push your init funcion into this array
+$.visualizePlugins = [];
+
+})(jQuery);
+
+
From 32d94bb6fb3d089cbbc61dfe275a440d9a69da59 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 22:00:58 +0200
Subject: [PATCH 136/168] less wide graphs
---
public/site_assets/mmcFE/js/custom.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/site_assets/mmcFE/js/custom.js b/public/site_assets/mmcFE/js/custom.js
index fcecd8e7..ab1b5167 100644
--- a/public/site_assets/mmcFE/js/custom.js
+++ b/public/site_assets/mmcFE/js/custom.js
@@ -19,7 +19,7 @@ $(function () {
// calculate width of graph so it doesnt overflow its parent div
//var chart_width = ($(this).parent('div').width()) - 60;
// hack to statically set width as something is broken with div width calculation - anni
- var chart_width = $(document).width() - 340;
+ var chart_width = $(document).width() - 400;
if (statsType == 'line' || statsType == 'pie') {
$(this).hide().visualize({
From 12843fab14d51d476d70b1259cea26e0d894b44a Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 22:01:18 +0200
Subject: [PATCH 137/168] adding new master template for tooltips
---
public/templates/mmcFE/master.tpl | 1 +
1 file changed, 1 insertion(+)
diff --git a/public/templates/mmcFE/master.tpl b/public/templates/mmcFE/master.tpl
index aff628f4..4c3204dc 100644
--- a/public/templates/mmcFE/master.tpl
+++ b/public/templates/mmcFE/master.tpl
@@ -11,6 +11,7 @@
+
From 2b5642327224d1893cfb9ec60ab8c37205fd2a52 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 22:01:34 +0200
Subject: [PATCH 138/168] adding line graphs in block stats
---
public/templates/mmcFE/statistics/blocks/default.tpl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl
index 0cfec471..6f9f7687 100644
--- a/public/templates/mmcFE/statistics/blocks/default.tpl
+++ b/public/templates/mmcFE/statistics/blocks/default.tpl
@@ -1,5 +1,5 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Block Luck" BLOCK_STYLE="clear:none;"}
-
+
{section block $BLOCKSFOUND step=-1}
From e7bb725da444fbd982c6253dbd34173453fe4b85 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 22:03:21 +0200
Subject: [PATCH 139/168] remove decimals for expected shares in graph
---
public/templates/mmcFE/statistics/blocks/default.tpl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl
index 6f9f7687..515f5dbb 100644
--- a/public/templates/mmcFE/statistics/blocks/default.tpl
+++ b/public/templates/mmcFE/statistics/blocks/default.tpl
@@ -11,7 +11,7 @@
Expected Shares
{section block $BLOCKSFOUND step=-1}
- {(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)}
+ {round(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)}
{/section}
From 90640d345e085fa09cdb42994896430f475069f2 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 22:26:12 +0200
Subject: [PATCH 140/168] removing static-ish stats width, use table width
instead
---
public/site_assets/mmcFE/js/custom.js | 10 +---------
public/templates/mmcFE/statistics/blocks/default.tpl | 9 +++++----
public/templates/mmcFE/statistics/user/default.tpl | 4 ++--
3 files changed, 8 insertions(+), 15 deletions(-)
diff --git a/public/site_assets/mmcFE/js/custom.js b/public/site_assets/mmcFE/js/custom.js
index ab1b5167..76e967c6 100644
--- a/public/site_assets/mmcFE/js/custom.js
+++ b/public/site_assets/mmcFE/js/custom.js
@@ -16,19 +16,12 @@ $(function () {
var statsType = 'area';
}
- // calculate width of graph so it doesnt overflow its parent div
- //var chart_width = ($(this).parent('div').width()) - 60;
- // hack to statically set width as something is broken with div width calculation - anni
- var chart_width = $(document).width() - 400;
-
if (statsType == 'line' || statsType == 'pie') {
$(this).hide().visualize({
type: statsType,
// 'bar', 'area', 'pie', 'line'
- width: chart_width,
height: '240px',
colors: ['#6fb9e8', '#ec8526', '#9dc453', '#ddd74c'],
-
lineDots: 'double',
interaction: true,
multiHover: 5,
@@ -43,9 +36,8 @@ $(function () {
});
} else {
$(this).hide().visualize({
- type: statsType,
// 'bar', 'area', 'pie', 'line'
- width: chart_width,
+ type: statsType,
height: '240px',
colors: ['#6fb9e8', '#ec8526', '#9dc453', '#ddd74c']
});
diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl
index 515f5dbb..8bcad85b 100644
--- a/public/templates/mmcFE/statistics/blocks/default.tpl
+++ b/public/templates/mmcFE/statistics/blocks/default.tpl
@@ -1,5 +1,6 @@
-{include file="global/block_header.tpl" BLOCK_HEADER="Block Luck" BLOCK_STYLE="clear:none;"}
-
+{include file="global/block_header.tpl" BLOCK_HEADER="Block Shares" BLOCK_STYLE="clear:none;"}
+
+ Block Shares
{section block $BLOCKSFOUND step=-1}
@@ -9,13 +10,13 @@
- Expected Shares
+ Expected
{section block $BLOCKSFOUND step=-1}
{round(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)}
{/section}
- Actual Shares
+ Actual
{section block $BLOCKSFOUND step=-1}
{$BLOCKSFOUND[block].shares}
{/section}
diff --git a/public/templates/mmcFE/statistics/user/default.tpl b/public/templates/mmcFE/statistics/user/default.tpl
index dc285321..debbd23a 100644
--- a/public/templates/mmcFE/statistics/user/default.tpl
+++ b/public/templates/mmcFE/statistics/user/default.tpl
@@ -1,8 +1,8 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Your Average Hourly Hash Rate" BUTTONS=array(mine,pool,both)}
{if is_array($YOURHASHRATES)}
-
- Your Hashrate
+
+ Your Hashrate
From 6f858188ad53a743307ece3369644e89b618cbf9 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Thu, 13 Jun 2013 22:59:19 +0200
Subject: [PATCH 141/168] Adding pool and combined hashrate graphs
* Moving from My Graph to its own section: Hashrate Graphs
* Adding pool hashrate graph
* Adding combined hashrate graph and piechart
Fixes #187
---
public/include/classes/statistics.class.php | 29 ++++++++++++-
.../{user.inc.php => graphs.inc.php} | 2 +
public/templates/mmcFE/global/navigation.tpl | 2 +-
.../mmcFE/statistics/graphs/both.tpl | 43 +++++++++++++++++++
.../mmcFE/statistics/graphs/default.tpl | 5 +++
.../{user/default.tpl => graphs/mine.tpl} | 2 -
.../mmcFE/statistics/graphs/pool.tpl | 31 +++++++++++++
7 files changed, 110 insertions(+), 4 deletions(-)
rename public/include/pages/statistics/{user.inc.php => graphs.inc.php} (74%)
create mode 100644 public/templates/mmcFE/statistics/graphs/both.tpl
create mode 100644 public/templates/mmcFE/statistics/graphs/default.tpl
rename public/templates/mmcFE/statistics/{user/default.tpl => graphs/mine.tpl} (83%)
create mode 100644 public/templates/mmcFE/statistics/graphs/pool.tpl
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index 3bcebcfb..46ab5cb5 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -293,7 +293,6 @@ class Statistics {
/**
* get Hourly hashrate for a user
- * Not working yet since I was not able to solve this via SQL queries
* @param account_id int User ID
* @return data array NOT FINISHED YET
**/
@@ -321,6 +320,34 @@ class Statistics {
$this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
return false;
}
+
+ /**
+ * get Hourly hashrate for the pool
+ * @param none
+ * @return data array NOT FINISHED YET
+ **/
+ public function getHourlyHashrateByPool() {
+ $this->debug->append("STA " . __METHOD__, 4);
+ if ($data = $this->memcache->get(__FUNCTION__)) return $data;
+ $stmt = $this->mysqli->prepare("
+ SELECT
+ ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ") / 3600 / 1000) AS hashrate,
+ HOUR(s.time) AS hour
+ FROM " . $this->share->getTableName() . " AS s
+ WHERE time < NOW() - INTERVAL 1 HOUR
+ AND time > NOW() - INTERVAL 25 HOUR
+ GROUP BY HOUR(time)
+ ");
+ if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) {
+ while ($row = $result->fetch_assoc()) {
+ $aData[$row['hour']] = $row['hashrate'];
+ }
+ return $this->memcache->setCache(__FUNCTION__, $aData);
+ }
+ // Catchall
+ $this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
+ return false;
+ }
}
$statistics = new Statistics($debug, $mysqli, $config, $share, $user, $block, $memcache);
diff --git a/public/include/pages/statistics/user.inc.php b/public/include/pages/statistics/graphs.inc.php
similarity index 74%
rename from public/include/pages/statistics/user.inc.php
rename to public/include/pages/statistics/graphs.inc.php
index 13b3ba5b..cf62bddf 100644
--- a/public/include/pages/statistics/user.inc.php
+++ b/public/include/pages/statistics/graphs.inc.php
@@ -6,8 +6,10 @@ if (!defined('SECURITY'))
if ($user->isAuthenticated()) {
$aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']);
+ $aPoolHourlyHashRates = $statistics->getHourlyHashrateByPool();
// Propagate content our template
$smarty->assign("YOURHASHRATES", $aHourlyHashRates);
+ $smarty->assign("POOLHASHRATES", $aPoolHourlyHashRates);
$smarty->assign("CONTENT", "default.tpl");
}
?>
diff --git a/public/templates/mmcFE/global/navigation.tpl b/public/templates/mmcFE/global/navigation.tpl
index 9beb87cb..c53f61c7 100644
--- a/public/templates/mmcFE/global/navigation.tpl
+++ b/public/templates/mmcFE/global/navigation.tpl
@@ -5,7 +5,6 @@
@@ -23,6 +22,7 @@
Getting Started
diff --git a/public/templates/mmcFE/statistics/graphs/both.tpl b/public/templates/mmcFE/statistics/graphs/both.tpl
new file mode 100644
index 00000000..ff760be1
--- /dev/null
+++ b/public/templates/mmcFE/statistics/graphs/both.tpl
@@ -0,0 +1,43 @@
+{if is_array($YOURHASHRATES) && is_array($POOLHASHRATES)}
+
+{foreach from=array('area','pie') item=chartType}
+
+ Your vs Pool Hashrate
+
+
+
+{for $i=date('G') to 23}
+ {$i}:00
+{/for}
+{for $i=0 to date('G', time () - 60 * 60)}
+ {$i}:00
+{/for}
+
+
+
+
+ {$smarty.session.USERDATA.username}
+{for $i=date('G') to 23}
+ {$YOURHASHRATES.$i|default:"0"}
+{/for}
+{for $i=0 to date('G', time() - 60 * 60)}
+ {$YOURHASHRATES.$i|default:"0"}
+{/for}
+
+
+ Pool
+{for $i=date('G') to 23}
+ {$POOLHASHRATES.$i|default:"0"}
+{/for}
+{for $i=0 to date('G', time() - 60 * 60)}
+ {$POOLHASHRATES.$i|default:"0"}
+{/for}
+
+
+
+
+{/foreach}
+
+{else}
+
No shares available to start calculations
+{/if}
diff --git a/public/templates/mmcFE/statistics/graphs/default.tpl b/public/templates/mmcFE/statistics/graphs/default.tpl
new file mode 100644
index 00000000..c325a4c6
--- /dev/null
+++ b/public/templates/mmcFE/statistics/graphs/default.tpl
@@ -0,0 +1,5 @@
+{include file="global/block_header.tpl" BLOCK_HEADER="24h Hashrate Statistics" BUTTONS=array(mine,pool,both)}
+{include file="{$smarty.request.page}/{$smarty.request.action}/mine.tpl"}
+{include file="{$smarty.request.page}/{$smarty.request.action}/pool.tpl"}
+{include file="{$smarty.request.page}/{$smarty.request.action}/both.tpl"}
+{include file="global/block_footer.tpl"}
diff --git a/public/templates/mmcFE/statistics/user/default.tpl b/public/templates/mmcFE/statistics/graphs/mine.tpl
similarity index 83%
rename from public/templates/mmcFE/statistics/user/default.tpl
rename to public/templates/mmcFE/statistics/graphs/mine.tpl
index debbd23a..fe217f2f 100644
--- a/public/templates/mmcFE/statistics/user/default.tpl
+++ b/public/templates/mmcFE/statistics/graphs/mine.tpl
@@ -1,4 +1,3 @@
-{include file="global/block_header.tpl" BLOCK_HEADER="Your Average Hourly Hash Rate" BUTTONS=array(mine,pool,both)}
{if is_array($YOURHASHRATES)}
@@ -30,4 +29,3 @@
{else}
No shares available to start calculations
{/if}
-{include file="global/block_footer.tpl"}
diff --git a/public/templates/mmcFE/statistics/graphs/pool.tpl b/public/templates/mmcFE/statistics/graphs/pool.tpl
new file mode 100644
index 00000000..ba2ed4e5
--- /dev/null
+++ b/public/templates/mmcFE/statistics/graphs/pool.tpl
@@ -0,0 +1,31 @@
+{if is_array($POOLHASHRATES)}
+
+
+ Pool Hashrate
+
+
+
+{for $i=date('G') to 23}
+ {$i}:00
+{/for}
+{for $i=0 to date('G', time () - 60 * 60)}
+ {$i}:00
+{/for}
+
+
+
+
+ Pool
+{for $i=date('G') to 23}
+ {$POOLHASHRATES.$i|default:"0"}
+{/for}
+{for $i=0 to date('G', time() - 60 * 60)}
+ {$POOLHASHRATES.$i|default:"0"}
+{/for}
+
+
+
+
+{else}
+
No shares available to start calculations
+{/if}
From 6f3912b6a2a4b56352b6badcffb28384503396e4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 09:58:54 +0200
Subject: [PATCH 142/168] fixed worker name in mail body
---
cronjobs/notifications.php | 1 +
public/templates/mail/notifications/idle_worker.tpl | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php
index a6b8b101..ec61002a 100755
--- a/cronjobs/notifications.php
+++ b/cronjobs/notifications.php
@@ -31,6 +31,7 @@ if (empty($aWorkers)) {
$aData = $aWorker;
$aData['username'] = $user->getUserName($aWorker['account_id']);
$aData['subject'] = 'IDLE Worker : ' . $aWorker['username'];
+ $aData['worker'] = $aWorker['username'];
$aData['email'] = $user->getUserEmail($aData['username']);
if (!$notification->sendNotification($aWorker['account_id'], 'idle_worker', $aData))
verbose($notification->getError() . "\n");
diff --git a/public/templates/mail/notifications/idle_worker.tpl b/public/templates/mail/notifications/idle_worker.tpl
index 6d1c282c..3ef12840 100644
--- a/public/templates/mail/notifications/idle_worker.tpl
+++ b/public/templates/mail/notifications/idle_worker.tpl
@@ -1,7 +1,9 @@
-One of your workers is currently IDLE: {$DATA.username}
+One of your workers is currently IDLE: {$DATA.worker}
+We have not received any shares for this worker in the past 10 minutes.
Since monitoring is enabled for this worker, this notification was sent.
+
Please check your workers!
From bee35325dcabb94e6a46d384305f9cb82be6b74a Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 11:38:00 +0200
Subject: [PATCH 143/168] Only show 20 blocks for block graph
Graph dynamically expands if the blocks don't fit so it's now limited to
20 which should always fit well enough.
---
public/templates/mmcFE/statistics/blocks/default.tpl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl
index 8bcad85b..cde7dcb3 100644
--- a/public/templates/mmcFE/statistics/blocks/default.tpl
+++ b/public/templates/mmcFE/statistics/blocks/default.tpl
@@ -3,7 +3,7 @@
Block Shares
-{section block $BLOCKSFOUND step=-1}
+{section block $BLOCKSFOUND step=-1 max=20}
{$BLOCKSFOUND[block].height}
{/section}
@@ -11,13 +11,13 @@
Expected
-{section block $BLOCKSFOUND step=-1}
+{section block $BLOCKSFOUND step=-1 max=20}
{round(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)}
{/section}
Actual
-{section block $BLOCKSFOUND step=-1}
+{section block $BLOCKSFOUND step=-1 max=20}
{$BLOCKSFOUND[block].shares}
{/section}
From c0870b3a481df187ca7ccd3ec05110f921e0c2c2 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 11:58:41 +0200
Subject: [PATCH 144/168] Added more generic pool stats
* added pool efficiency based on valid and invalid shares
* added estimated shares progress based on est and valid shares
---
.../templates/mmcFE/statistics/pool/authenticated.tpl | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/public/templates/mmcFE/statistics/pool/authenticated.tpl b/public/templates/mmcFE/statistics/pool/authenticated.tpl
index 5c67bbcd..822609e8 100644
--- a/public/templates/mmcFE/statistics/pool/authenticated.tpl
+++ b/public/templates/mmcFE/statistics/pool/authenticated.tpl
@@ -12,7 +12,11 @@
{($GLOBAL.hashrate / 1000)|number_format:"3"} Mhash/s
-
+
+ {100 - (100 / $GLOBAL.roundshares.valid * $GLOBAL.roundshares.invalid)|number_format:"2"} %
+
+
+
{$GLOBAL.workers}
@@ -32,8 +36,8 @@
{$ESTTIME|seconds_to_words}
-
- {(pow(2, 32 - $GLOBAL.config.targetdiff) * $DIFFICULTY)|number_format:"0"}
+
+ {(pow(2, 32 - $GLOBAL.config.targetdiff) * $DIFFICULTY)|number_format:"0"} (done: {(100 / (pow(2, 32 - $GLOBAL.config.targetdiff) * $DIFFICULTY) * $GLOBAL.roundshares.valid)|number_format:"2"} %)
From d23d5773688c2a06cebb3c226f5ccc6735448fb5 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 12:36:17 +0200
Subject: [PATCH 145/168] always show 2 digit pool efficiency
---
public/templates/mmcFE/statistics/pool/authenticated.tpl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/templates/mmcFE/statistics/pool/authenticated.tpl b/public/templates/mmcFE/statistics/pool/authenticated.tpl
index 822609e8..edc0e0ba 100644
--- a/public/templates/mmcFE/statistics/pool/authenticated.tpl
+++ b/public/templates/mmcFE/statistics/pool/authenticated.tpl
@@ -13,7 +13,7 @@
- {100 - (100 / $GLOBAL.roundshares.valid * $GLOBAL.roundshares.invalid)|number_format:"2"} %
+ {(100 - (100 / $GLOBAL.roundshares.valid * $GLOBAL.roundshares.invalid))|number_format:"2"} %
From 4c4202bc1b56094b5969aa8ac7dcbb3fda3272d9 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 13:22:50 +0200
Subject: [PATCH 146/168] fixing notice warning when not logged in
---
public/include/smarty_globals.inc.php | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index 257d33d4..5c4bde10 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -7,15 +7,16 @@ if (!defined('SECURITY'))
// Globally available variables
$debug->append('Global smarty variables', 3);
+// Defaults to get rid of PHP Notice warnings
+$dDifficulty = 1;
+
// Only run these if the user is logged in
if ($_SESSION['AUTHENTICATED']) {
$aRoundShares = $statistics->getRoundShares();
- if ($bitcoin->can_connect() === true){
+ if ($bitcoin->can_connect() === true)
$dDifficulty = $bitcoin->query('getdifficulty');
- } else {
- $dDifficulty = 1;
- }
}
+
// Fetch some data
$iCurrentActiveWorkers = $worker->getCountAllActiveWorkers();
$iCurrentPoolHashrate = $statistics->getCurrentHashrate();
From 0817befaaa79a3386c8061f40fdc455233093951 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 13:51:06 +0200
Subject: [PATCH 147/168] Further cleanup to reduce PHP notice warnings
---
public/include/classes/statistics.class.php | 1 +
public/include/classes/user.class.php | 2 +-
public/include/pages/account/edit.inc.php | 4 ++--
public/include/pages/account/notifications.inc.php | 2 +-
public/include/pages/account/workers.inc.php | 6 ++++--
public/include/pages/admin/user.inc.php | 10 +++++-----
public/include/pages/statistics/graphs.inc.php | 9 +++++----
public/include/pages/statistics/pool.inc.php | 2 ++
public/include/smarty_globals.inc.php | 3 ++-
public/templates/mmcFE/account/edit/default.tpl | 2 +-
.../mmcFE/statistics/pool/contributors_hashrate.tpl | 2 +-
11 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index 46ab5cb5..6f56453b 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -311,6 +311,7 @@ class Statistics {
GROUP BY HOUR(time)
");
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result()) {
+ $aData = array();
while ($row = $result->fetch_assoc()) {
$aData[$row['hour']] = $row['hashrate'];
}
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 20ff072d..49de7b5f 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -552,7 +552,7 @@ class User {
**/
public function isAuthenticated() {
$this->debug->append("STA " . __METHOD__, 4);
- if ($_SESSION['AUTHENTICATED'] == true && ! $this->isLocked($_SESSION['USERDATA']['id']) && $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'])
+ if (@$_SESSION['AUTHENTICATED'] == true && ! $this->isLocked($_SESSION['USERDATA']['id']) && $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'])
return true;
// Catchall
$this->logoutUser();
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index a4859c8f..92b8f1e1 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -5,10 +5,10 @@ if (!defined('SECURITY'))
die('Hacking attempt');
if ($user->isAuthenticated()) {
- if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST['do']) {
+ if ( ! $user->checkPin($_SESSION['USERDATA']['id'], @$_POST['authPin']) && @$_POST['do']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN','TYPE' => 'errormsg');
} else {
- switch ($_POST['do']) {
+ switch (@$_POST['do']) {
case 'cashOut':
if ($setting->getValue('manual_payout_active') == 1) {
$_SESSION['POPUP'][] = array('CONTENT' => 'A manual payout is in progress. Please try again later.', 'TYPE' => 'errormsg');
diff --git a/public/include/pages/account/notifications.inc.php b/public/include/pages/account/notifications.inc.php
index 87fd6217..3f013ed0 100644
--- a/public/include/pages/account/notifications.inc.php
+++ b/public/include/pages/account/notifications.inc.php
@@ -3,7 +3,7 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
if ($user->isAuthenticated()) {
- if ($_REQUEST['do'] == 'save') {
+ if (@$_REQUEST['do'] == 'save') {
if ($notification->updateSettings($_SESSION['USERDATA']['id'], $_REQUEST['data'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Updated notification settings');
} else {
diff --git a/public/include/pages/account/workers.inc.php b/public/include/pages/account/workers.inc.php
index 78556424..ccdae2b8 100644
--- a/public/include/pages/account/workers.inc.php
+++ b/public/include/pages/account/workers.inc.php
@@ -4,7 +4,7 @@
if (!defined('SECURITY')) die('Hacking attempt');
if ($user->isAuthenticated()) {
- switch ($_REQUEST['do']) {
+ switch (@$_REQUEST['do']) {
case 'delete':
if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed');
@@ -31,7 +31,9 @@ if ($user->isAuthenticated()) {
$aWorkers = $worker->getWorkers($_SESSION['USERDATA']['id']);
if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'errormsg');
- $smarty->assign('CONTENT', 'default.tpl');
$smarty->assign('WORKERS', $aWorkers);
}
+
+$smarty->assign('CONTENT', 'default.tpl');
+
?>
diff --git a/public/include/pages/admin/user.inc.php b/public/include/pages/admin/user.inc.php
index 11808edb..9bb9ecee 100644
--- a/public/include/pages/admin/user.inc.php
+++ b/public/include/pages/admin/user.inc.php
@@ -12,18 +12,18 @@ if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) {
$aRoundShares = $statistics->getRoundShares();
// Change account lock
-if ($_POST['do'] == 'lock') {
+if (@$_POST['do'] == 'lock') {
$supress_master = 1;
$user->changeLocked($_POST['account_id']);
}
// Change account admin
-if ($_POST['do'] == 'admin') {
+if (@$_POST['do'] == 'admin') {
$supress_master = 1;
$user->changeAdmin($_POST['account_id']);
}
-if ($_POST['query']) {
+if (@$_POST['query']) {
// Fetch requested users
$aUsers = $statistics->getAllUserStats($_POST['query']);
@@ -40,10 +40,10 @@ if ($_POST['query']) {
$aUser['payout']['est_payout'] = round($aUser['payout']['est_block'] - $aUser['payout']['est_donation'] - $aUser['payout']['est_fee'], 3);
$aUsers[$iKey] = $aUser;
}
+ // Assign our variables
+ $smarty->assign("USERS", $aUsers);
}
-// Assign our variables
-$smarty->assign("USERS", $aUsers);
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
diff --git a/public/include/pages/statistics/graphs.inc.php b/public/include/pages/statistics/graphs.inc.php
index cf62bddf..f7016835 100644
--- a/public/include/pages/statistics/graphs.inc.php
+++ b/public/include/pages/statistics/graphs.inc.php
@@ -7,9 +7,10 @@ if (!defined('SECURITY'))
if ($user->isAuthenticated()) {
$aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']);
$aPoolHourlyHashRates = $statistics->getHourlyHashrateByPool();
- // Propagate content our template
- $smarty->assign("YOURHASHRATES", $aHourlyHashRates);
- $smarty->assign("POOLHASHRATES", $aPoolHourlyHashRates);
- $smarty->assign("CONTENT", "default.tpl");
}
+
+// Propagate content our template
+$smarty->assign("YOURHASHRATES", @$aHourlyHashRates);
+$smarty->assign("POOLHASHRATES", @$aPoolHourlyHashRates);
+$smarty->assign("CONTENT", "default.tpl");
?>
diff --git a/public/include/pages/statistics/pool.inc.php b/public/include/pages/statistics/pool.inc.php
index fc546e72..9650681e 100644
--- a/public/include/pages/statistics/pool.inc.php
+++ b/public/include/pages/statistics/pool.inc.php
@@ -27,6 +27,8 @@ $aBlockData = $aBlocksFoundData[0];
// Estimated time to find the next block
$iCurrentPoolHashrate = $statistics->getCurrentHashrate();
+$iCurrentPoolHashrate == 0 ? $iCurrentPoolHashrate = 1 : true;
+
// Time in seconds, not hours, using modifier in smarty to translate
$iEstTime = $dDifficulty * pow(2,32) / ($iCurrentPoolHashrate * 1000);
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index 5c4bde10..c8231a49 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -9,9 +9,10 @@ $debug->append('Global smarty variables', 3);
// Defaults to get rid of PHP Notice warnings
$dDifficulty = 1;
+$aRoundShares = 1;
// Only run these if the user is logged in
-if ($_SESSION['AUTHENTICATED']) {
+if (@$_SESSION['AUTHENTICATED']) {
$aRoundShares = $statistics->getRoundShares();
if ($bitcoin->can_connect() === true)
$dDifficulty = $bitcoin->query('getdifficulty');
diff --git a/public/templates/mmcFE/account/edit/default.tpl b/public/templates/mmcFE/account/edit/default.tpl
index f48ef67f..69861d61 100644
--- a/public/templates/mmcFE/account/edit/default.tpl
+++ b/public/templates/mmcFE/account/edit/default.tpl
@@ -23,7 +23,7 @@
diff --git a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
index 9086427a..2392af09 100644
--- a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
+++ b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
@@ -28,7 +28,7 @@
n/a
{$GLOBAL.userdata.username}
{$GLOBAL.userdata.hashrate}
- {$estday|number_format:"3"}
+ {$estday|number_format:"3"|default:"n/a"}
{($estday * $GLOBAL.price)|default:"n/a"|number_format:"2"}
{/if}
From 006f4d7f8a00a6a944f90baea8b3312a0b016e47 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 16:17:34 +0200
Subject: [PATCH 148/168] updated PPS payout to support block share stats for
users
---
cronjobs/pps_payout.php | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php
index efdbfc94..06d4f3b4 100755
--- a/cronjobs/pps_payout.php
+++ b/cronjobs/pps_payout.php
@@ -93,12 +93,27 @@ if (empty($aAllBlocks)) {
// Go through blocks and archive/delete shares that have been accounted for
foreach ($aAllBlocks as $iIndex => $aBlock) {
- $dummy = $iIndex - 1;
- if ($config['archive_shares'] && $aBlock['share_id'] < $iLastShareId) {
- $share->moveArchive($aBlock['share_id'], $aBlock['id'], @$aAllBlocks[$dummy]['share_id']);
+ // If we are running through more than one block, check for previous share ID
+ $iLastBlockShare = @$aAllBlocks[$iIndex - 1]['share_id'] ? @$aAllBlocks[$iIndex - 1]['share_id'] : 0;
+ // Per account statistics
+ $aAccountShares = $share->getSharesForAccounts(@$iLastBlockShare, $aBlock['share_id']);
+ foreach ($aAccountShares as $key => $aData) {
+ if (!$statistics->updateShareStatistics($aData, $aBlock['id']))
+ verbose("Failed to update stats for this block on : " . $aData['username'] . "\n");
}
- if ($aBlock['share_id'] < $iLastShareId && !$share->deleteAccountedShares($aBlock['share_id'], @$aAllBlocks[$dummy]['share_id'])) {
- verbose("\nERROR : Failed to delete accounted shares from " . $aBlock['share_id'] . " to " . @$aAllBlocks[$dummy]['share_id'] . ", aborting!\n");
+ // Move shares to archive
+ if ($config['archive_shares'] && $aBlock['share_id'] < $iLastShareId) {
+ if (!$share->moveArchive($aBlock['share_id'], $aBlock['id'], @$iLastBlockShare))
+ verbose("Archving failed\n");
+ }
+ // Delete shares
+ if ($aBlock['share_id'] < $iLastShareId && !$share->deleteAccountedShares($aBlock['share_id'], $iLastBlockShare)) {
+ verbose("\nERROR : Failed to delete accounted shares from " . $aBlock['share_id'] . " to " . $iLastBlockShare . ", aborting!\n");
+ exit(1);
+ }
+ // Mark this block as accounted for
+ if (!$block->setAccounted($aBlock['id'])) {
+ verbose("\nERROR : Failed to mark block as accounted! Aborting!\n");
exit(1);
}
}
From ca1237c11cc4ea6982e75e90a5001d37edd3f24d Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 17:52:56 +0200
Subject: [PATCH 149/168] fixing admin user information table format
---
public/templates/mmcFE/admin/user/default.tpl | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl
index 8cfc263a..82955741 100644
--- a/public/templates/mmcFE/admin/user/default.tpl
+++ b/public/templates/mmcFE/admin/user/default.tpl
@@ -67,7 +67,7 @@
{sectionelse}
-
+
{/section}
@@ -77,11 +77,12 @@
Username
E-Mail
Shares
- Hashrate
- Est. Donation
- Est. Payout
- Balance
+ Hashrate
+ Est. Donation
+ Est. Payout
+ Balance
Admin
+ Locked
From b7b0ab92984ca00efc0d03b147a8873c23bdcaf9 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 18:55:17 +0300
Subject: [PATCH 150/168] Update README.md
Adding new donor.
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index c7e8998a..ae08e1fc 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ These people have supported this project with a donation:
* [obigal](https://github.com/obigal)
* [vias](https://github.com/vias79)
+* [WKNiGHT](https://github.com/WKNiGHT-)
Requirements
============
From 91ef2caaab7663b744098832b2eeff04d4e37ec9 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 10:07:40 +0200
Subject: [PATCH 151/168] Added cronjob to pre-cache statistics
This will fix #199 and help on loading times for the website in case
caches are empty. Caches are pre-filled by a cron so the website only
does it as a fall back. Check Ticket for details.
---
cronjobs/run-crons.sh | 2 +-
cronjobs/statistics.php | 41 +++++++++++++++++++++
public/include/classes/statistics.class.php | 23 ++++++++----
3 files changed, 58 insertions(+), 8 deletions(-)
create mode 100755 cronjobs/statistics.php
diff --git a/cronjobs/run-crons.sh b/cronjobs/run-crons.sh
index 5f9179dc..f5cbaee7 100755
--- a/cronjobs/run-crons.sh
+++ b/cronjobs/run-crons.sh
@@ -16,7 +16,7 @@ PIDFILE='/tmp/mmcfe-ng-cron.pid'
CRONHOME='.'
# List of cruns to execute
-CRONS="findblock.php proportional_payout.php blockupdate.php auto_payout.php tickerupdate.php notifications.php"
+CRONS="findblock.php proportional_payout.php blockupdate.php auto_payout.php tickerupdate.php notifications.php statistics.php"
# Additional arguments to pass to cronjobs
CRONARGS="-v"
diff --git a/cronjobs/statistics.php b/cronjobs/statistics.php
new file mode 100755
index 00000000..03aad394
--- /dev/null
+++ b/cronjobs/statistics.php
@@ -0,0 +1,41 @@
+#!/usr/bin/php
+setGetCache(false);
+
+// Since fetching from cache is disabled, overwrite our stats
+if (!$statistics->getRoundShares())
+ verbose("Unable to fetch and store current round shares\n");
+if (!$statistics->getTopContributors('shares'))
+ verbose("Unable to fetch and store top share contributors\n");
+if (!$statistics->getTopContributors('hashes'))
+ verbose("Unable to fetch and store top hashrate contributors\n");
+if (!$statistics->getCurrentHashrate())
+ verbose("Unable to fetch and store pool hashrate\n");
+// Admin specific statistics, we cache the global query due to slowness
+if (!$statistics->getAllUserStats('%'))
+ verbose("Unable to fetch and store admin panel full user list\n");
+
+?>
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index 6f56453b..f9f2ea9a 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -13,6 +13,7 @@ if (!defined('SECURITY'))
class Statistics {
private $sError = '';
private $table = 'statistics_shares';
+ private $getcache = true;
public function __construct($debug, $mysqli, $config, $share, $user, $block, $memcache) {
$this->debug = $debug;
@@ -34,6 +35,14 @@ class Statistics {
return $this->sError;
}
+ // Disable fetching values from cache
+ public function setGetCache($set=false) {
+ $this->getcache = $set;
+ }
+ public function getGetCache() {
+ return $this->getcache;
+ }
+
private function checkStmt($bState) {
if ($bState ===! true) {
$this->debug->append("Failed to prepare statement: " . $this->mysqli->error);
@@ -88,7 +97,7 @@ class Statistics {
**/
public function getCurrentHashrate() {
$this->debug->append("STA " . __METHOD__, 4);
- if ($data = $this->memcache->get(__FUNCTION__)) return $data;
+ if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
");
@@ -122,7 +131,7 @@ class Statistics {
**/
public function getRoundShares() {
$this->debug->append("STA " . __METHOD__, 4);
- if ($data = $this->memcache->get(__FUNCTION__)) return $data;
+ if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
( SELECT IFNULL(count(id), 0)
@@ -147,7 +156,7 @@ class Statistics {
**/
public function getUserShares($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
- if ($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("
SELECT
(
@@ -181,7 +190,7 @@ class Statistics {
**/
public function getAllUserStats($filter='%') {
$this->debug->append("STA " . __METHOD__, 4);
- if ($data = $this->memcache->get(__FUNCTION__ . $filter)) return $data;
+ if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $filter)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
a.id AS id,
@@ -255,7 +264,7 @@ class Statistics {
**/
public function getTopContributors($type='shares', $limit=15) {
$this->debug->append("STA " . __METHOD__, 4);
- if ($data = $this->memcache->get(__FUNCTION__ . $type . $limit)) return $data;
+ if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $type . $limit)) return $data;
switch ($type) {
case 'shares':
$stmt = $this->mysqli->prepare("
@@ -329,7 +338,7 @@ class Statistics {
**/
public function getHourlyHashrateByPool() {
$this->debug->append("STA " . __METHOD__, 4);
- if ($data = $this->memcache->get(__FUNCTION__)) return $data;
+ if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ") / 3600 / 1000) AS hashrate,
@@ -343,7 +352,7 @@ class Statistics {
while ($row = $result->fetch_assoc()) {
$aData[$row['hour']] = $row['hashrate'];
}
- return $this->memcache->setCache(__FUNCTION__, $aData);
+ return $this->memcache->setCache(__FUNCTION__, @$aData);
}
// Catchall
$this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
From 4f3e1e9ccb8e1fb4f297462e8af2d6836e0b1529 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 10:40:36 +0200
Subject: [PATCH 152/168] Adding support for API currencies
Since some altcoins are not listed with USD yet @vias79 suggested adding
different API target currencies. This commit will add the feature and
closes #201.
---
public/include/config/global.inc.dist.php | 3 ++-
public/include/smarty_globals.inc.php | 1 +
public/templates/mmcFE/global/header.tpl | 2 +-
.../templates/mmcFE/statistics/pool/contributors_hashrate.tpl | 2 +-
4 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php
index b41d9110..29a46658 100644
--- a/public/include/config/global.inc.dist.php
+++ b/public/include/config/global.inc.dist.php
@@ -23,7 +23,8 @@ define('SALT', 'PLEASEMAKEMESOMETHINGRANDOM');
$config = array(
'price' => array(
'url' => 'https://btc-e.com/api/2',
- 'target' => '/ltc_usd/ticker'
+ 'target' => '/ltc_usd/ticker',
+ 'currency' => 'USD' // Used in ministats template
),
'ap_threshold' => array(
'min' => 1,
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index c8231a49..d55318d8 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -39,6 +39,7 @@ $aGlobal = array(
'blockexplorer' => $config['blockexplorer'],
'chaininfo' => $config['chaininfo'],
'config' => array(
+ 'price' => array( 'currency' => $config['price']['currency'] ),
'targetdiff' => $config['difficulty'],
'currency' => $config['currency'],
'txfee' => $config['txfee'],
diff --git a/public/templates/mmcFE/global/header.tpl b/public/templates/mmcFE/global/header.tpl
index a4b23f4b..fd625758 100644
--- a/public/templates/mmcFE/global/header.tpl
+++ b/public/templates/mmcFE/global/header.tpl
@@ -4,7 +4,7 @@
- {$GLOBAL.config.currency}/usd: {$GLOBAL.price|default:"n/a"|number_format:"4"}
+ {$GLOBAL.config.currency}/{$GLOBAL.config.price.currency}: {$GLOBAL.price|default:"n/a"|number_format:"4"}
Pool Hashrate: {($GLOBAL.hashrate / 1000)|number_format:"3"} MH/s
Pool Sharerate: {$GLOBAL.sharerate|number_format:"2"} Shares/s
Pool Workers: {$GLOBAL.workers}
diff --git a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
index 2392af09..222902c7 100644
--- a/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
+++ b/public/templates/mmcFE/statistics/pool/contributors_hashrate.tpl
@@ -7,7 +7,7 @@
User Name
KH/s
{$GLOBAL.config.currency}/Day
- USD/Day
+ {$GLOBAL.config.price.currency}/Day
From c93b6068a3c150a1dbafca55696f42bc80606b20 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 10:45:34 +0200
Subject: [PATCH 153/168] Update README.md
Added feature: support for various scrypt based coins.
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index ae08e1fc..817aab98 100644
--- a/README.md
+++ b/README.md
@@ -84,6 +84,10 @@ The following feature have been implemented so far:
* New blocks found in pool
* Auto Payout
* Manual Payout
+* Support for various Scrypt based coins via config
+ * MNC
+ * LTC
+ * ...
Installation
============
From fa7f61c436b420f68e41f5854ce540b4d9b61c77 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 11:17:15 +0200
Subject: [PATCH 154/168] Adding transaction fees to transaction class
This will add back the transaction fees. Prior to this commit the pool
had to cover the transaction fees. Now for each transaction the full
balance is transferred (RPC Daemon will remove the TX Fee) but two
transactions are added. One for the Debig and one TXFee.
Fixes #203.
**Requires database upgrade with supplied SQL file**
---
cronjobs/auto_payout.php | 2 +-
public/include/classes/transaction.class.php | 6 +++---
public/include/pages/account/edit.inc.php | 4 ++--
public/templates/mmcFE/account/transactions/default.tpl | 1 +
sql/issue_203_transactions_upgrade.sql | 1 +
5 files changed, 8 insertions(+), 6 deletions(-)
create mode 100644 sql/issue_203_transactions_upgrade.sql
diff --git a/cronjobs/auto_payout.php b/cronjobs/auto_payout.php
index 366298e1..6bf36dd4 100755
--- a/cronjobs/auto_payout.php
+++ b/cronjobs/auto_payout.php
@@ -61,7 +61,7 @@ if (! empty($users)) {
}
// Create transaction record
- if ($transaction->addTransaction($aUserData['id'], $dBalance, 'Debit_AP', NULL, $aUserData['coin_address'])) {
+ if ($transaction->addTransaction($aUserData['id'], $dBalance - $config['txfee'], 'Debit_AP', NULL, $aUserData['coin_address']) && $transaction->addTransaction($aUserData['id'], $config['txfee'], 'TXFee', NULL, $aUserData['coin_address'])) {
// Notify user via mail
$aMailData['email'] = $user->getUserEmail($user->getUserName($aUserData['id']));
$aMailData['subject'] = 'Auto Payout Completed';
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index 3609de73..a6acd15c 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -147,7 +147,7 @@ class Transaction {
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE (
( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
- t.type IN ('Donation_PPS','Fee_PPS')
+ t.type IN ('Donation_PPS','Fee_PPS','TXFee')
)
) AS t3");
if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $this->config['confirmations'], $this->config['confirmations']) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
@@ -194,7 +194,7 @@ class Transaction {
WHERE
(
( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
- ( t.type IN ('Donation_PPS', 'Fee_PPS') )
+ ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') )
)
AND t.account_id = ?
) AS t3,
@@ -216,7 +216,7 @@ class Transaction {
WHERE
(
( t.type IN ('Donation','Fee') AND b.confirmations < ? ) OR
- ( t.type IN ('Donation_PPS', 'Fee_PPS') )
+ ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') )
)
AND t.account_id = ?
) AS t5
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index 92b8f1e1..2610f8f6 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -29,7 +29,7 @@ if ($user->isAuthenticated()) {
}
if ($continue == true) {
// Send balance to address, mind fee for transaction!
- try {
+ try {
if ($setting->getValue('auto_payout_active') == 0) {
$bitcoin->sendtoaddress($sCoinAddress, $dBalance);
} else {
@@ -42,7 +42,7 @@ if ($user->isAuthenticated()) {
}
}
// Set balance to 0, add to paid out, insert to ledger
- if ($continue == true && $transaction->addTransaction($_SESSION['USERDATA']['id'], $dBalance, 'Debit_MP', NULL, $sCoinAddress)) {
+ if ($continue == true && $transaction->addTransaction($_SESSION['USERDATA']['id'], $dBalance - $config['txfee'], 'Debit_MP', NULL, $sCoinAddress) && $transaction->addTransaction($_SESSION['USERDATA']['id'], $config['txfee'], 'TXFee', NULL, $sCoinAddress) ) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Transaction completed', 'TYPE' => 'success');
$aMailData['email'] = $user->getUserEmail($user->getUserName($_SESSION['USERDATA']['id']));
$aMailData['amount'] = $dBalance;
diff --git a/public/templates/mmcFE/account/transactions/default.tpl b/public/templates/mmcFE/account/transactions/default.tpl
index d2393450..c76e9fae 100644
--- a/public/templates/mmcFE/account/transactions/default.tpl
+++ b/public/templates/mmcFE/account/transactions/default.tpl
@@ -24,6 +24,7 @@
or $TRANSACTIONS[transaction].type == 'Donation_PPS'
or $TRANSACTIONS[transaction].type == 'Debit_AP'
or $TRANSACTIONS[transaction].type == 'Debit_MP'
+ or $TRANSACTIONS[transaction].type == 'TXFee'
)}
{$TRANSACTIONS[transaction].id}
diff --git a/sql/issue_203_transactions_upgrade.sql b/sql/issue_203_transactions_upgrade.sql
new file mode 100644
index 00000000..9c824b89
--- /dev/null
+++ b/sql/issue_203_transactions_upgrade.sql
@@ -0,0 +1 @@
+ALTER TABLE `transactions` CHANGE `type` `type` ENUM( 'Credit', 'Debit_MP', 'Debit_AP', 'Donation', 'Fee', 'Orphan_Credit', 'Orphan_Fee', 'Orphan_Donation', 'Credit_PPS', 'Fee_PPS', 'Donation_PPS', 'TXFee' ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ;
From 9bde3d979cf15b638590b726d99b4f358539e337 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 11:19:05 +0200
Subject: [PATCH 155/168] removed whitespace
---
public/include/pages/account/edit.inc.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index 2610f8f6..5b717cee 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -29,7 +29,7 @@ if ($user->isAuthenticated()) {
}
if ($continue == true) {
// Send balance to address, mind fee for transaction!
- try {
+ try {
if ($setting->getValue('auto_payout_active') == 0) {
$bitcoin->sendtoaddress($sCoinAddress, $dBalance);
} else {
From fe0beb16170daa44334cb730a68035dcd7b787ea Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 11:25:54 +0200
Subject: [PATCH 156/168] changed output in auto_payout
---
cronjobs/auto_payout.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cronjobs/auto_payout.php b/cronjobs/auto_payout.php
index 6bf36dd4..7e5609fc 100755
--- a/cronjobs/auto_payout.php
+++ b/cronjobs/auto_payout.php
@@ -76,7 +76,7 @@ if (! empty($users)) {
}
} else {
- verbose("INSUFF_TXFEE\n");
+ verbose("SKIPPED\n");
}
}
} else {
From 647b522b00b1f7ae17f23ab9c21a1aebe1f7c719 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 15:00:56 +0200
Subject: [PATCH 157/168] Adding percentage colulmn to block template
This shows the % of shares found for a block compared to the expected
value.
---
public/templates/mmcFE/statistics/blocks/default.tpl | 2 ++
1 file changed, 2 insertions(+)
diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl
index cde7dcb3..3d7afdde 100644
--- a/public/templates/mmcFE/statistics/blocks/default.tpl
+++ b/public/templates/mmcFE/statistics/blocks/default.tpl
@@ -42,6 +42,7 @@ target and network difficulty and assuming a zero variance scenario.
Difficulty
Expected Shares
Actual Shares
+ Percentage
@@ -60,6 +61,7 @@ target and network difficulty and assuming a zero variance scenario.
{$BLOCKSFOUND[block].difficulty|number_format:"2"}
{(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)|number_format}
{$BLOCKSFOUND[block].shares|number_format}
+ {($BLOCKSFOUND[block].shares / (pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty) * 100)|number_format:"2"}
{/section}
From 905898700ae3bb5447ec3b8c9c0862316b6b48b2 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 16:35:27 +0200
Subject: [PATCH 158/168] adding per-user share statistics to cron
---
cronjobs/statistics.php | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/cronjobs/statistics.php b/cronjobs/statistics.php
index 03aad394..d4fe65e0 100755
--- a/cronjobs/statistics.php
+++ b/cronjobs/statistics.php
@@ -38,4 +38,12 @@ if (!$statistics->getCurrentHashrate())
if (!$statistics->getAllUserStats('%'))
verbose("Unable to fetch and store admin panel full user list\n");
+// Per user share statistics based on all shares submitted
+$stmt = $mysqli->prepare("SELECT DISTINCT SUBSTRING_INDEX( `username` , '.', 1 ) AS username FROM " . $share->getTableName());
+if ($stmt && $stmt->execute() && $result = $stmt->get_result()) {
+ while ($row = $result->fetch_assoc()) {
+ if (!$statistics->getUserShares($user->getUserId($row['username'])))
+ verbose("Failed to fetch and store user stats for " . $row['username'] . "\n");
+ }
+}
?>
From b532bbca51b5a20e6f6c7cd6283d8b3d83e77dc4 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Mon, 17 Jun 2013 16:42:17 +0200
Subject: [PATCH 159/168] Do not mark PPS transactions as unconfirmed
Fixes #206
---
public/include/classes/transaction.class.php | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php
index a6acd15c..38e1b429 100644
--- a/public/include/classes/transaction.class.php
+++ b/public/include/classes/transaction.class.php
@@ -203,10 +203,7 @@ class Transaction {
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE
- (
- ( t.type IN ('Credit','Bonus') AND b.confirmations < ? ) OR
- ( t.type = 'Credit_PPS' )
- )
+ t.type IN ('Credit','Bonus') AND b.confirmations < ?
AND t.account_id = ?
) AS t4,
(
@@ -215,8 +212,7 @@ class Transaction {
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE
(
- ( t.type IN ('Donation','Fee') AND b.confirmations < ? ) OR
- ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') )
+ t.type IN ('Donation','Fee') AND b.confirmations < ?
)
AND t.account_id = ?
) AS t5
From d3fa335e2c730254375f71fce6088a755dda0ecd Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 10:14:13 +0200
Subject: [PATCH 160/168] Ensure we are able to fetch the upstream share
* If a block was found but the upstream share is not inserted, bail out
* Next run should find the upstream share if it was added properly
Should address #189 but maybe not a fix yet.
---
cronjobs/findblock.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php
index 0538d94c..dae9b432 100755
--- a/cronjobs/findblock.php
+++ b/cronjobs/findblock.php
@@ -82,9 +82,9 @@ foreach ($aAllBlocks as $iIndex => $aBlock) {
$iCurrentUpstreamId = $share->getUpstreamId();
$iAccountId = $user->getUserId($share->getUpstreamFinder());
} else {
- verbose("Unable to fetch blocks upstream share\n");
+ verbose("Unable to fetch blocks upstream share. Aborting!\n");
verbose($share->getError() . "\n");
- continue;
+ exit;
}
// Fetch share information
if (!$iPreviousShareId = $block->getLastShareId()) {
From 34509051e29213e27398505342258bdbd5602790 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 18 Jun 2013 09:29:25 +0200
Subject: [PATCH 161/168] Properly detect if we did find an upstream share
Avoid returning true even if no share was found.
Addresses #189
---
cronjobs/findblock.php | 107 ++++++++++++-------------
public/include/classes/share.class.php | 3 +-
2 files changed, 55 insertions(+), 55 deletions(-)
diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php
index dae9b432..cb1e7dba 100755
--- a/cronjobs/findblock.php
+++ b/cronjobs/findblock.php
@@ -39,9 +39,8 @@ if ( $bitcoin->can_connect() === true ){
// Nothing to do so bail out
if (empty($aTransactions['transactions'])) {
- verbose("No new transactions since last block\n");
+ verbose("No new RPC transactions since last block\n");
} else {
-
// Table header
verbose("Blockhash\t\tHeight\tAmount\tConfirmations\tDiff\t\tTime\t\t\tStatus\n");
@@ -66,65 +65,65 @@ if (empty($aTransactions['transactions'])) {
}
}
-verbose("\n\n");
+verbose("\n");
// Now with our blocks added we can scan for their upstream shares
$aAllBlocks = $block->getAllUnaccounted('ASC');
if (empty($aAllBlocks)) {
verbose("No new unaccounted blocks found\n");
-}
+} else {
+ // Loop through our unaccounted blocks
+ verbose("\nBlock ID\tBlock Height\tShare ID\tShares\tFinder\t\t\tStatus\n");
+ foreach ($aAllBlocks as $iIndex => $aBlock) {
+ if (empty($aBlock['share_id'])) {
+ // Fetch this blocks upstream ID
+ if ($share->setUpstream($block->getLastUpstreamId())) {
+ $iCurrentUpstreamId = $share->getUpstreamId();
+ $iAccountId = $user->getUserId($share->getUpstreamFinder());
+ } else {
+ verbose("\nUnable to fetch blocks upstream share. Aborting!\n");
+ verbose($share->getError() . "\n");
+ exit;
+ }
+ // Fetch share information
+ if (!$iPreviousShareId = $block->getLastShareId()) {
+ $iPreviousShareId = 0;
+ verbose("\nUnable to find highest share ID found so far\n");
+ verbose("If this is your first block, this is normal\n\n");
+ }
+ $iRoundShares = $share->getRoundShares($iPreviousShareId, $iCurrentUpstreamId);
-// Loop through our unaccounted blocks
-verbose("Block ID\tBlock Height\tShare ID\tShares\tFinder\t\t\tStatus\n");
-foreach ($aAllBlocks as $iIndex => $aBlock) {
- if (empty($aBlock['share_id'])) {
- // Fetch this blocks upstream ID
- if ($share->setUpstream($block->getLastUpstreamId())) {
- $iCurrentUpstreamId = $share->getUpstreamId();
- $iAccountId = $user->getUserId($share->getUpstreamFinder());
- } else {
- verbose("Unable to fetch blocks upstream share. Aborting!\n");
- verbose($share->getError() . "\n");
- exit;
- }
- // Fetch share information
- if (!$iPreviousShareId = $block->getLastShareId()) {
- $iPreviousShareId = 0;
- verbose("\nUnable to find highest share ID found so far\n");
- verbose("If this is your first block, this is normal\n\n");
- }
- $iRoundShares = $share->getRoundShares($iPreviousShareId, $iCurrentUpstreamId);
+ // Store new information
+ $strStatus = "OK";
+ if (!$block->setShareId($aBlock['id'], $iCurrentUpstreamId))
+ $strStatus = "Share ID Failed";
+ if (!$block->setFinder($aBlock['id'], $iAccountId))
+ $strStatus = "Finder Failed";
+ if (!$block->setShares($aBlock['id'], $iRoundShares))
+ $strStatus = "Shares Failed";
+ if ($config['block_bonus'] > 0 && !$transaction->addTransaction($iAccountId, $config['block_bonus'], 'Bonus', $aBlock['id'])) {
+ $strStatus = "Bonus Failed";
+ }
- // Store new information
- $strStatus = "OK";
- if (!$block->setShareId($aBlock['id'], $iCurrentUpstreamId))
- $strStatus = "Share ID Failed";
- if (!$block->setFinder($aBlock['id'], $iAccountId))
- $strStatus = "Finder Failed";
- if (!$block->setShares($aBlock['id'], $iRoundShares))
- $strStatus = "Shares Failed";
- if ($config['block_bonus'] > 0 && !$transaction->addTransaction($iAccountId, $config['block_bonus'], 'Bonus', $aBlock['id'])) {
- $strStatus = "Bonus Failed";
- }
+ verbose(
+ $aBlock['id'] . "\t\t"
+ . $aBlock['height'] . "\t\t"
+ . $iCurrentUpstreamId . "\t\t"
+ . $iRoundShares . "\t"
+ . "[$iAccountId] " . $user->getUserName($iAccountId) . "\t\t"
+ . $strStatus
+ . "\n"
+ );
- verbose(
- $aBlock['id'] . "\t\t"
- . $aBlock['height'] . "\t\t"
- . $iCurrentUpstreamId . "\t\t"
- . $iRoundShares . "\t"
- . "[$iAccountId] " . $user->getUserName($iAccountId) . "\t\t"
- . $strStatus
- . "\n"
- );
-
- // Notify users
- $aAccounts = $notification->getNotificationAccountIdByType('new_block');
- if (is_array($aAccounts)) {
- foreach ($aAccounts as $account_id) {
- $aMailData['height'] = $aBlock['height'];
- $aMailData['subject'] = 'New Block';
- $aMailData['email'] = $user->getUserEmail($user->getUserName($account_id));
- $aMailData['shares'] = $iRoundShares;
- $notification->sendNotification($account_id, 'new_block', $aMailData);
+ // Notify users
+ $aAccounts = $notification->getNotificationAccountIdByType('new_block');
+ if (is_array($aAccounts)) {
+ foreach ($aAccounts as $account_id) {
+ $aMailData['height'] = $aBlock['height'];
+ $aMailData['subject'] = 'New Block';
+ $aMailData['email'] = $user->getUserEmail($user->getUserName($account_id));
+ $aMailData['shares'] = $iRoundShares;
+ $notification->sendNotification($account_id, 'new_block', $aMailData);
+ }
}
}
}
diff --git a/public/include/classes/share.class.php b/public/include/classes/share.class.php
index 1033f92c..85935a2d 100644
--- a/public/include/classes/share.class.php
+++ b/public/include/classes/share.class.php
@@ -187,7 +187,8 @@ class Share {
ORDER BY id ASC LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('i', $last) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
- return true;
+ if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
+ return true;
}
// Catchall
return false;
From 3f0c3884aa35563eaca220881b0ee6403905946a Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Fri, 14 Jun 2013 15:20:30 +0200
Subject: [PATCH 162/168] Adding some more information for PPS to sidebar
* Added user share rate to sidebar for PPS
* Added estimated 24h LTC payout based on PPS value and share rate
Addresses #160
---
public/include/classes/statistics.class.php | 25 ++++++++++++++++++++-
public/include/smarty_globals.inc.php | 1 +
public/templates/mmcFE/global/sidebar.tpl | 10 ++++++++-
3 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php
index f9f2ea9a..a30aba1b 100644
--- a/public/include/classes/statistics.class.php
+++ b/public/include/classes/statistics.class.php
@@ -199,7 +199,7 @@ class Statistics {
a.username AS username,
a.donate_percent AS donate_percent,
a.email AS email,
- COUNT(s.id) AS shares
+ COUNT(s.id) AS shares
FROM " . $this->user->getTableName() . " AS a
LEFT JOIN " . $this->share->getTableName() . " AS s
ON a.username = SUBSTRING_INDEX( s.username, '.', 1 )
@@ -219,6 +219,7 @@ class Statistics {
* @return data integer Current Hashrate in khash/s
**/
public function getUserHashrate($account_id) {
+ $this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate
@@ -234,6 +235,28 @@ class Statistics {
return false;
}
+ /**
+ * Same as getUserHashrate for Sharerate
+ * @param account_id integer User ID
+ * @return data integer Current Sharerate in shares/s
+ **/
+ public function getUserSharerate($account_id) {
+ $this->debug->append("STA " . __METHOD__, 4);
+ if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
+ $stmt = $this->mysqli->prepare("
+ SELECT COUNT(s.id)/600 AS sharerate
+ FROM " . $this->share->getTableName() . " AS s,
+ " . $this->user->getTableName() . " AS u
+ WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 )
+ AND s.time > DATE_SUB(now(), INTERVAL 10 MINUTE)
+ AND u.id = ?");
+ if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result() )
+ return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_object()->sharerate);
+ // Catchall
+ $this->debug->append("Failed to fetch sharerate: " . $this->mysqli->error);
+ return false;
+ }
+
/**
* Get hashrate for a specific worker
* @param worker_id int Worker ID to fetch hashrate for
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index d55318d8..2d33a173 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -59,6 +59,7 @@ if (@$_SESSION['USERDATA']['id']) {
// Other userdata that we can cache savely
$aGlobal['userdata']['shares'] = $statistics->getUserShares($_SESSION['USERDATA']['id']);
$aGlobal['userdata']['hashrate'] = $statistics->getUserHashrate($_SESSION['USERDATA']['id']);
+ $aGlobal['userdata']['sharerate'] = $statistics->getUserSharerate($_SESSION['USERDATA']['id']);
// Some estimations
$aGlobal['userdata']['est_block'] = round(( (int)$aGlobal['userdata']['shares']['valid'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
diff --git a/public/templates/mmcFE/global/sidebar.tpl b/public/templates/mmcFE/global/sidebar.tpl
index 34018785..450be70d 100644
--- a/public/templates/mmcFE/global/sidebar.tpl
+++ b/public/templates/mmcFE/global/sidebar.tpl
@@ -14,9 +14,17 @@
{$GLOBAL.userdata.hashrate|number_format} KH/s
{if $GLOBAL.config.payout_system == 'pps'}
+
+ Share Rate
+ {$GLOBAL.userdata.sharerate|number_format:"2"} S/s
+
PPS Value
- {$GLOBAL.ppsvalue}
+ {$GLOBAL.ppsvalue}
+
+
+ {$GLOBAL.config.currency} in 24h
+ {($GLOBAL.userdata.sharerate * 24 * 60 * 60 * $GLOBAL.ppsvalue)|number_format:"8"}
{/if}
{if $GLOBAL.config.payout_system != 'pps'}
From 82f696164524c7d2813e2c3409ae7b04307e2164 Mon Sep 17 00:00:00 2001
From: Sebastian Grewe
Date: Tue, 18 Jun 2013 10:22:43 +0200
Subject: [PATCH 163/168] Adding PPS specific sidebar
* Adding PPS sidebar to seperate the HTML code
* Added PPS specific globals section if need be some day
* Added payout detection to master template for sidebar
* Added 7 days and 14 days estimates
Fixes #160
---
public/include/smarty_globals.inc.php | 16 +++--
public/templates/mmcFE/global/sidebar.tpl | 18 ------
public/templates/mmcFE/global/sidebar_pps.tpl | 61 +++++++++++++++++++
public/templates/mmcFE/master.tpl | 6 +-
4 files changed, 77 insertions(+), 24 deletions(-)
create mode 100644 public/templates/mmcFE/global/sidebar_pps.tpl
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index 2d33a173..923b7263 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -61,11 +61,17 @@ if (@$_SESSION['USERDATA']['id']) {
$aGlobal['userdata']['hashrate'] = $statistics->getUserHashrate($_SESSION['USERDATA']['id']);
$aGlobal['userdata']['sharerate'] = $statistics->getUserSharerate($_SESSION['USERDATA']['id']);
- // Some estimations
- $aGlobal['userdata']['est_block'] = round(( (int)$aGlobal['userdata']['shares']['valid'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
- $aGlobal['userdata']['est_fee'] = round(($config['fees'] / 100) * $aGlobal['userdata']['est_block'], 3);
- $aGlobal['userdata']['est_donation'] = round((( $aGlobal['userdata']['donate_percent'] / 100) * ($aGlobal['userdata']['est_block'] - $aGlobal['userdata']['est_fee'])), 3);
- $aGlobal['userdata']['est_payout'] = round($aGlobal['userdata']['est_block'] - $aGlobal['userdata']['est_donation'] - $aGlobal['userdata']['est_fee'], 3);
+ switch ($config['payout_system']) {
+ case 'pps':
+ break;
+ default:
+ // Some estimations
+ $aGlobal['userdata']['est_block'] = round(( (int)$aGlobal['userdata']['shares']['valid'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
+ $aGlobal['userdata']['est_fee'] = round(($config['fees'] / 100) * $aGlobal['userdata']['est_block'], 3);
+ $aGlobal['userdata']['est_donation'] = round((( $aGlobal['userdata']['donate_percent'] / 100) * ($aGlobal['userdata']['est_block'] - $aGlobal['userdata']['est_fee'])), 3);
+ $aGlobal['userdata']['est_payout'] = round($aGlobal['userdata']['est_block'] - $aGlobal['userdata']['est_donation'] - $aGlobal['userdata']['est_fee'], 3);
+ break;
+ }
}
// Make it available in Smarty
diff --git a/public/templates/mmcFE/global/sidebar.tpl b/public/templates/mmcFE/global/sidebar.tpl
index 450be70d..58d49c67 100644
--- a/public/templates/mmcFE/global/sidebar.tpl
+++ b/public/templates/mmcFE/global/sidebar.tpl
@@ -13,21 +13,6 @@
Hashrate
{$GLOBAL.userdata.hashrate|number_format} KH/s
-{if $GLOBAL.config.payout_system == 'pps'}
-
- Share Rate
- {$GLOBAL.userdata.sharerate|number_format:"2"} S/s
-
-
- PPS Value
- {$GLOBAL.ppsvalue}
-
-
- {$GLOBAL.config.currency} in 24h
- {($GLOBAL.userdata.sharerate * 24 * 60 * 60 * $GLOBAL.ppsvalue)|number_format:"8"}
-
-{/if}
-{if $GLOBAL.config.payout_system != 'pps'}
Unpaid Shares
@@ -39,7 +24,6 @@
Pool Valid
{$GLOBAL.roundshares.valid|number_format}
-{/if}
Round Shares
@@ -55,7 +39,6 @@
Your Invalid
{$GLOBAL.userdata.shares.invalid|number_format}
-{if $GLOBAL.config.payout_system != 'pps'}
{$GLOBAL.config.currency} Round Estimate
@@ -75,7 +58,6 @@
Payout
{$GLOBAL.userdata.est_payout|number_format:"3"}
-{/if}
{$GLOBAL.config.currency} Account Balance
Confirmed {$GLOBAL.userdata.balance.confirmed|default:"0"}
diff --git a/public/templates/mmcFE/global/sidebar_pps.tpl b/public/templates/mmcFE/global/sidebar_pps.tpl
new file mode 100644
index 00000000..b7aa8617
--- /dev/null
+++ b/public/templates/mmcFE/global/sidebar_pps.tpl
@@ -0,0 +1,61 @@
+
diff --git a/public/templates/mmcFE/master.tpl b/public/templates/mmcFE/master.tpl
index 4c3204dc..8709e974 100644
--- a/public/templates/mmcFE/master.tpl
+++ b/public/templates/mmcFE/master.tpl
@@ -47,7 +47,11 @@