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/classes/user.class.php b/public/include/classes/user.class.php index d6582676..2b5f093e 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -26,26 +26,28 @@ class User { public function getError() { return $this->sError; } - public function getUserName($id) { return $this->getSingle($id, 'username', 'id'); } - public function getUserId($username) { return $this->getSingle($username, 'id', 'username', 's'); } - public function getUserEmail($username) { return $this->getSingle($username, 'email', 'username', 's'); } - + public function getUserAdmin($id) { + return $this->getSingle($id, 'admin', 'id'); + } public function getUserToken($id) { return $this->getSingle($id, 'token', 'id'); } - public function getIdFromToken($token) { return $this->getSingle($token, 'id', 'token', 's'); } + public function isAdmin($id) { + if ($this->getUserAdmin($id) == 1) return true; + return false; + } public function setUserToken($id) { $field = array( @@ -56,6 +58,18 @@ class User { return $this->updateSingle($id, $field); } + /** + * Fetch all users for administrative tasks + * @param none + * @return data array All users with db columns as array fields + **/ + public function getUsers($filter='%') { + $stmt = $this->mysqli->prepare("SELECT * FROM " . $this->getTableName() . " WHERE username LIKE ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param('s', $filter) && $stmt->execute() && $result = $stmt->get_result()) { + return $result->fetch_all(MYSQLI_ASSOC); + } + } + /** * Check user login * @param username string Username @@ -266,15 +280,15 @@ class User { private function checkUserPassword($username, $password) { $this->debug->append("STA " . __METHOD__, 4); $user = array(); - $stmt = $this->mysqli->prepare("SELECT username, id FROM $this->table WHERE username=? AND pass=? LIMIT 1"); + $stmt = $this->mysqli->prepare("SELECT username, id, 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(); - $stmt->bind_result($row_username, $row_id); + $stmt->bind_result($row_username, $row_id, $row_admin); $stmt->fetch(); $stmt->close(); // Store the basic login information - $this->user = array('username' => $row_username, 'id' => $row_id); + $this->user = array('username' => $row_username, 'id' => $row_id, 'admin' => $row_admin); return $username === $row_username; } return false; diff --git a/public/include/pages/admin.inc.php b/public/include/pages/admin.inc.php new file mode 100644 index 00000000..4409a769 --- /dev/null +++ b/public/include/pages/admin.inc.php @@ -0,0 +1,15 @@ +isAdmin($_SESSION['USERDATA']['id'])) { + header("HTTP/1.1 404 Page not found"); + die(); +} + +// Tempalte specifics +$smarty->assign("CONTENT", "default.tpl"); +?> diff --git a/public/include/pages/admin/user.inc.php b/public/include/pages/admin/user.inc.php new file mode 100644 index 00000000..cc961f44 --- /dev/null +++ b/public/include/pages/admin/user.inc.php @@ -0,0 +1,37 @@ +isAdmin($_SESSION['USERDATA']['id'])) { + header("HTTP/1.1 404 Page not found"); + die(); +} + +$aRoundShares = $statistics->getRoundShares(); + +if ($_POST['query']) { + // Fetch requested users + $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['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); + $aUsers[$iKey] = $aUser; + } +} + +// Assign our variables +$smarty->assign("USERS", $aUsers); + +// Tempalte specifics +$smarty->assign("CONTENT", "default.tpl"); +?> diff --git a/public/site_assets/mmcFE/css/style.css b/public/site_assets/mmcFE/css/style.css index a41aef4c..8133150a 100644 --- a/public/site_assets/mmcFE/css/style.css +++ b/public/site_assets/mmcFE/css/style.css @@ -465,6 +465,12 @@ a:hover { .block table tr th.right{ text-align: right; } +.block table tr td.center{ + text-align: center; +} +.block table tr th.center{ + text-align: center; +} .block table tr td.delete a { color: #666; } diff --git a/public/site_assets/mmcFE/images/first.png b/public/site_assets/mmcFE/images/first.png new file mode 100644 index 00000000..6f11fcb0 Binary files /dev/null and b/public/site_assets/mmcFE/images/first.png differ diff --git a/public/site_assets/mmcFE/images/last.png b/public/site_assets/mmcFE/images/last.png new file mode 100644 index 00000000..72079357 Binary files /dev/null and b/public/site_assets/mmcFE/images/last.png differ diff --git a/public/site_assets/mmcFE/images/next.png b/public/site_assets/mmcFE/images/next.png new file mode 100644 index 00000000..4a2f9d4e Binary files /dev/null and b/public/site_assets/mmcFE/images/next.png differ diff --git a/public/site_assets/mmcFE/images/prev.png b/public/site_assets/mmcFE/images/prev.png new file mode 100644 index 00000000..15d1584b Binary files /dev/null and b/public/site_assets/mmcFE/images/prev.png differ diff --git a/public/site_assets/mmcFE/js/custom.js b/public/site_assets/mmcFE/js/custom.js index 1e047555..2070bd82 100644 --- a/public/site_assets/mmcFE/js/custom.js +++ b/public/site_assets/mmcFE/js/custom.js @@ -66,6 +66,10 @@ $(function () { widgets: ['zebra'] }); + $("table.pagesort") + .tablesorter({ widgets: ['zebra'] }) + .tablesorterPager({ positionFixed: false, container: $("#pager") }); + $('.block table tr th.header').css('cursor', 'pointer'); // Check / uncheck all checkboxes diff --git a/public/templates/mmcFE/admin/default.tpl b/public/templates/mmcFE/admin/default.tpl new file mode 100644 index 00000000..60cdf352 --- /dev/null +++ b/public/templates/mmcFE/admin/default.tpl @@ -0,0 +1,3 @@ +{include file="global/block_header.tpl" BLOCK_HEADER="Admin Panel"} +

Welcome to the admin panel. Please select an option from the drop-down menu.

+{include file="global/block_footer.tpl"} diff --git a/public/templates/mmcFE/admin/user/default.tpl b/public/templates/mmcFE/admin/user/default.tpl new file mode 100644 index 00000000..5386a84f --- /dev/null +++ b/public/templates/mmcFE/admin/user/default.tpl @@ -0,0 +1,77 @@ +{include file="global/block_header.tpl" BLOCK_HEADER="Query User Database"} +
+ + + + +
+{include file="global/block_footer.tpl"} + +{include file="global/block_header.tpl" BLOCK_HEADER="User Information"} +
+
+
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + +{section name=user loop=$USERS|default} + + + + + + + + + + + +{sectionelse} + + + +{/section} + + + + + + + + + + + + + + +
IDUsernameE-MailHashrate  Shares  Est. Donation  Est. Payout   Balance   Admin
{$USERS[user].id}{$USERS[user].username}{$USERS[user].email}{$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"} + +
IDUsernameE-MailHashrateSharesEst. DonationEst. PayoutBalanceAdmin
+{include file="global/block_footer.tpl"} diff --git a/public/templates/mmcFE/global/navigation.tpl b/public/templates/mmcFE/global/navigation.tpl index 3830006b..13172478 100644 --- a/public/templates/mmcFE/global/navigation.tpl +++ b/public/templates/mmcFE/global/navigation.tpl @@ -10,7 +10,13 @@ {/if} - {if $smarty.session.AUTHENTICATED|default:"0" == 1 && $GLOBAL.userdata.admin == 1}
  • Admin Panel
  • {/if} + {if $smarty.session.AUTHENTICATED|default:"0" == 1 && $GLOBAL.userdata.admin == 1} +
  • Admin Panel + +
  • + {/if}
  • Statistics