Enhance Torn Vault Tracker: Add documentation, improve exception handling, and update styles
Deploy website via FTP / Deploy (push) Skipped

- Updated .gitignore to exclude new directories and files.
- Enhanced config.php with detailed PHPDoc comments for better clarity.
- Refactored functions.php to include PHPDoc comments and improve code readability.
- Added custom exceptions in exceptions.php with detailed documentation.
- Improved utilities.php with better documentation and error handling.
- Updated index.php with structured comments and improved readability.
- Refined style.css for better visual consistency.
- Introduced phpcs.xml for coding style checks and standards enforcement.
This commit is contained in:
Keith Solomon
2026-08-03 12:07:16 -05:00
parent 8c68e81c2e
commit 2811fc83e5
8 changed files with 656 additions and 462 deletions
+2
View File
@@ -3,3 +3,5 @@ backup/
debug.log debug.log
data/* data/*
!data/.gitkeep !data/.gitkeep
.claude/
phpcs-results.txt
+13 -3
View File
@@ -1,10 +1,20 @@
<?php <?php
// Configuration file for settings like database and API keys /**
* Configuration file for settings like database and API keys
*
* PHP version 8.1+
*
* @category Configuration
* @package TornVaultTracker
* @author Keith Solomon <ksolomon@gmail.com>
* @license Unlicense https://unlicense.org/
* @link https://github.com/ksolomon/TornVaultTracker
*/
// Database settings // Database settings
define('DB_DSN', 'sqlite:data/vault.db'); // Path to your SQLite database define('DB_DSN', 'sqlite:data/vault.db'); // Path to your SQLite database
define('DB_USER', null); // Not needed for SQLite define('DB_USER', null); // Not needed for SQLite
define('DB_PASSWORD', null); // Not needed for SQLite define('DB_PASSWORD', null); // Not needed for SQLite
// User-specific keys for accessing logs // User-specific keys for accessing logs
const USER_KEYS = [ const USER_KEYS = [
+226 -199
View File
@@ -1,199 +1,226 @@
<?php <?php
// Include settings from a separate configuration file /**
require_once __DIR__ . '/config.php'; * Functions for the Torn Vault Tracker application.
*
// Include utility functions * PHP version 8.1+
require_once 'includes/exceptions.php'; *
require_once 'includes/utilities.php'; * @category Functions
* @package TornVaultTracker
/** Returns a PDO connection to the database * @author Keith Solomon <ksolomon@gmail.com>
* This function creates the database connection and creates the database * @license Unlicense https://unlicense.org/
* file if it doesn't exist, and the vault table if it doesn't exist. * @link https://github.com/ksolomon/TornVaultTracker
* */
* @return PDO
*/ // Include settings from configuration file
function getDatabaseConnection() { require_once __DIR__ . '/config.php';
static $pdo = null;
// Include utility functions
// SQL to create the vault table if it doesn't exist require_once 'includes/exceptions.php';
$createTableSQL = "CREATE TABLE IF NOT EXISTS vault ( require_once 'includes/utilities.php';
id TEXT PRIMARY KEY,
user TEXT NOT NULL, /**
timestamp INTEGER NOT NULL, * Returns a PDO connection to the database
description TEXT NOT NULL, * This function creates the database connection and creates the database
amount REAL NOT NULL * file if it doesn't exist, and the vault table if it doesn't exist.
);"; *
* @return PDO
if ($pdo === null) { */
try { function getDatabaseConnection() {
$pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD); static $pdo = null;
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// SQL to create the vault table if it doesn't exist
$pdo->exec($createTableSQL); $createTableSQL = "CREATE TABLE IF NOT EXISTS vault (
} catch (PDOException $e) { id TEXT PRIMARY KEY,
die("Database connection failed: " . $e->getMessage()); user TEXT NOT NULL,
} timestamp INTEGER NOT NULL,
} description TEXT NOT NULL,
amount REAL NOT NULL
return $pdo; );";
}
if ($pdo === null) {
/** Pulls and stores all vault transaction logs for a user from the Torn API. try {
* $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD);
* This function retrieves all transaction logs related to vault deposits and $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
* withdrawals for a specified user. It continues fetching logs until no more
* entries are available, and stores each entry in the database. Each log entry $pdo->exec($createTableSQL);
* is uniquely identified by its ID and includes details such as timestamp, } catch (PDOException $e) {
* description, and amount. The function requires the user's API key to die("Database connection failed: " . $e->getMessage());
* authenticate requests to the Torn API. }
* }
* @param string $user The user whose transaction logs are to be retrieved and stored.
*/ return $pdo;
function firstRun($user) { }
$apiKey = USER_KEYS[$user];
/**
$pdo = getDatabaseConnection(); * Pulls and stores all vault transaction logs for a user from the Torn API.
*
$to = time(); * This function retrieves all transaction logs related to vault deposits and
* withdrawals for a specified user. It continues fetching logs until no more
do { * entries are available, and stores each entry in the database. Each log entry
$url = "https://api.torn.com/v2/user?selections=log&log=5850,5851&to=$to"; * is uniquely identified by its ID and includes details such as timestamp,
$ch = curl_init($url); * description, and amount. The function requires the user's API key to
* authenticate requests to the Torn API.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); *
curl_setopt($ch, CURLOPT_HTTPHEADER, [ * @param string $user The user whose transaction logs are to be retrieved and stored.
'accept: application/json', *
"Authorization: ApiKey $apiKey" * @throws ApiKeyMissingException If the user does not have an API key configured.
]); * @throws CurlErrorException If there is an error during the API call.
* @throws Exception If there is an error decoding the JSON response or if the response is invalid.
$response = curl_exec($ch); *
* @return void
curl_close($ch); */
function firstRun($user) {
$data = json_decode($response, true); $apiKey = USER_KEYS[$user];
$pdo = getDatabaseConnection();
if (empty($data['log'])) { break; } $to = time();
foreach ($data['log'] as $key => $entry) { do {
$description = $entry['title']; $url = "https://api.torn.com/v2/user?selections=log&log=5850,5851&to=$to";
$timestamp = $entry['timestamp']; $ch = curl_init($url);
$amount = isset($entry['data']['deposited']) ? $entry['data']['deposited'] : -$entry['data']['withdrawn'];
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$stmt = $pdo->prepare('INSERT INTO vault (ID, user, timestamp, description, amount) VALUES (:id, :user, :timestamp, :description, :amount)'); curl_setopt(
$ch, CURLOPT_HTTPHEADER, [
$stmt->bindValue(':id', $key); 'accept: application/json',
$stmt->bindValue(':user', $user); "Authorization: ApiKey $apiKey"
$stmt->bindValue(':timestamp', $timestamp); ]
$stmt->bindValue(':description', $description); );
$stmt->bindValue(':amount', $amount);
$response = curl_exec($ch);
$stmt->execute();
} curl_close($ch);
$to = end($data['log'])['timestamp']; $data = json_decode($response, true);
} while (true);
} if (empty($data['log'])) {
break;
/** Retrieves the user's log entries from the Torn API }
*
* @param string $user The user to retrieve the log for foreach ($data['log'] as $key => $entry) {
* @param boolean $debug Whether to output debug information (default: false) $description = $entry['title'];
* $timestamp = $entry['timestamp'];
* @throws Exception If the user does not have an API key configured, $amount = isset($entry['data']['deposited']) ? $entry['data']['deposited'] : -$entry['data']['withdrawn'];
* if the API call fails, or if the log data is invalid
*/ $stmt = $pdo->prepare('INSERT INTO vault (ID, user, timestamp, description, amount) VALUES (:id, :user, :timestamp, :description, :amount)');
function getLog($user, $debug = false) {
$pdo = getDatabaseConnection(); $stmt->bindValue(':id', $key);
$stmt->bindValue(':user', $user);
ensureUserHasApiKey($user); $stmt->bindValue(':timestamp', $timestamp);
$stmt->bindValue(':description', $description);
$stmt = $pdo->query("SELECT MAX(timestamp) AS max_timestamp FROM vault WHERE user = '$user'"); $stmt->bindValue(':amount', $amount);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->execute();
$from = $row['max_timestamp']; }
$to = time();
$to = end($data['log'])['timestamp'];
$apiKey = USER_KEYS[$user]; } while (true);
$apiEndpoint = "https://api.torn.com/user/?selections=log&log=5850,5851&to=$to&from=$from&key=$apiKey"; }
$responseData = executeApiCall($apiEndpoint); /**
validateApiResponse($responseData); * Retrieves the user's log entries from the Torn API
*
$checkStmt = prepareCheckStatement($pdo); * @param string $user The user to retrieve the log for
$insertStmt = prepareInsertStatement($pdo); * @param boolean $debug Whether to output debug information (default: false)
*
processLogEntries($responseData['log'], $user, $checkStmt, $insertStmt, $debug); * @throws Exception If the user does not have an API key configured,
} * if the API call fails, or if the log data is invalid
*
/** Generate the current balance for a user or all users * @return void
* */
* @param string $name (optional) The user to get the balance for. If not provided, all users' balances will be added. function getLog($user, $debug = false) {
* $pdo = getDatabaseConnection();
* @return string The balance as a formatted string
*/ ensureUserHasApiKey($user);
function generateBalance($name=null) {
$balance = vaultLoop($name); $stmt = $pdo->query("SELECT MAX(timestamp) AS max_timestamp FROM vault WHERE user = '$user'");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return number_format($balance, 0); // Format the balance as an integer
} $from = $row['max_timestamp'];
$to = time();
/** Calculate the available vault space for a user or all users.
* $apiKey = USER_KEYS[$user];
* This function calculates the remaining space in the vault based on the $apiEndpoint = "https://api.torn.com/user/?selections=log&log=5850,5851&to=$to&from=$from&key=$apiKey";
* transactions for a specific user or all users. If a user is specified,
* the available space is calculated against a limit of 500,000,000. $responseData = executeApiCall($apiEndpoint);
* If no user is specified, the available space is calculated against a validateApiResponse($responseData);
* total vault limit of 1,000,000,000.
* $checkStmt = prepareCheckStatement($pdo);
* @param string|null $name (optional) The user to calculate the vault space for. $insertStmt = prepareInsertStatement($pdo);
* If not provided, calculates for all users.
* processLogEntries($responseData['log'], $user, $checkStmt, $insertStmt, $debug);
* @return string The available vault space as a formatted string. }
*/
/**
function getSpace($name=null) { * Generate the current balance for a user or all users
$space = vaultLoop($name); *
* @param string $name (optional) The user to get the balance for. If not provided, all users' balances will be added.
if ($name === null) { *
$space = 1000000000 - $space; * @return string The balance as a formatted string
} else { */
$space = 500000000 - $space; function generateBalance($name=null) {
} $balance = vaultLoop($name);
return number_format($space, 0); // Format the balance as an integer return number_format($balance, 0); // Format the balance as an integer
} }
/** Builds an HTML table of all transactions in the vault /**
* * Calculate the available vault space for a user or all users.
* Loops over all records in the vault and builds a table of the user, timestamp, *
* description and amount of each transaction. Amounts are formatted as integers. * This function calculates the remaining space in the vault based on the
* * transactions for a specific user or all users. If a user is specified,
* @return void * the available space is calculated against a limit of 500,000,000.
*/ * If no user is specified, the available space is calculated against a
function buildTable () { * total vault limit of 1,000,000,000.
$records = fetchVaultRecords(); *
* @param string|null $name (optional) The user to calculate the vault space for.
foreach ($records as $entry) { * If not provided, calculates for all users.
$user = $entry['user']; *
$timestamp = $entry['timestamp']; * @return string The available vault space as a formatted string.
$description = $entry['description']; */
$amount = $entry['amount']; function getSpace($name=null) {
$sign = getSign($amount); $space = vaultLoop($name);
if ($description == 'Vault withdraw') { if ($name === null) {
$class = 'debit'; $space = 1000000000 - $space;
$amount = substr($amount, 1); // Remove the negative sign } else {
} else { $space = 500000000 - $space;
$class = 'credit'; }
}
return number_format($space, 0); // Format the balance as an integer
$amount = number_format($amount, 0); // Format the amount as an integer }
echo '<tr class="'.$class.'">'; /**
echo '<td>'.$user.'</td>'; * Builds an HTML table of all transactions in the vault
echo '<td>'.date("F j, Y / H:i", $timestamp).'</td>'; *
echo '<td>'.$description.'</td>'; * Loops over all records in the vault and builds a table of the user, timestamp,
echo '<td>'.$sign.$amount.'</td>'; * description and amount of each transaction. Amounts are formatted as integers.
echo '</tr>'; *
} * @return void
} */
function buildTable () {
$records = fetchVaultRecords();
foreach ($records as $entry) {
$user = $entry['user'];
$timestamp = $entry['timestamp'];
$description = $entry['description'];
$amount = $entry['amount'];
$sign = getSign($amount);
if ($description == 'Vault withdraw') {
$class = 'debit';
$amount = substr($amount, 1); // Remove the negative sign
} else {
$class = 'credit';
}
$amount = number_format($amount, 0); // Format the amount as an integer
echo '<tr class="'.$class.'">';
echo '<td>'.$user.'</td>';
echo '<td>'.date("F j, Y / H:i", $timestamp).'</td>';
echo '<td>'.$description.'</td>';
echo '<td>'.$sign.$amount.'</td>';
echo '</tr>';
}
}
+88 -12
View File
@@ -1,24 +1,100 @@
<?php <?php
/**
* Custom exceptions for API interactions.
*
* PHP version 8.1+
*
* @category Exception
* @package TornVaultTracker
* @author Keith Solomon <ksolomon@gmail.com>
* @license Unlicense https://unlicense.org/
* @link https://github.com/ksolomon/Torn-Vault-Tracker
*/
/**
* Exception thrown when API key is missing.
*
* @category Exception
* @package TornVaultTracker
* @author Keith Solomon <ksolomon@gmail.com>
* @license Unlicense https://unlicense.org/
* @link https://github.com/ksolomon/Torn-Vault-Tracker
*/
class ApiKeyMissingException extends Exception { class ApiKeyMissingException extends Exception {
public function __construct($message, $code = 0, Throwable $previous = null) { /**
parent::__construct($message, $code, $previous); * Constructor.
} *
* @param string $message The exception message.
* @param int $code The exception code.
* @param Throwable $previous The previous throwable.
*/
public function __construct($message, $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
} }
/**
* Exception thrown on CURL errors.
*
* @category Exception
* @package TornVaultTracker
* @author Keith Solomon <ksolomon@gmail.com>
* @license Unlicense https://unlicense.org/
* @link https://github.com/ksolomon/Torn-Vault-Tracker
*/
class CurlErrorException extends Exception { class CurlErrorException extends Exception {
public function __construct($message, $code = 0, Throwable $previous = null) { /**
parent::__construct($message, $code, $previous); * Constructor.
} *
* @param string $message The exception message.
* @param int $code The exception code.
* @param Throwable $previous The previous throwable.
*/
public function __construct($message, $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
} }
/**
* Exception thrown on JSON data errors.
*
* @category Exception
* @package TornVaultTracker
* @author Keith Solomon <ksolomon@gmail.com>
* @license Unlicense https://unlicense.org/
* @link https://github.com/ksolomon/Torn-Vault-Tracker
*/
class JsonDataException extends Exception { class JsonDataException extends Exception {
public function __construct($message, $code = 0, Throwable $previous = null) { /**
parent::__construct($message, $code, $previous); * Constructor.
} *
* @param string $message The exception message.
* @param int $code The exception code.
* @param Throwable $previous The previous throwable.
*/
public function __construct($message, $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
} }
/**
* Exception thrown on API validation errors.
*
* @category Exception
* @package TornVaultTracker
* @author Keith Solomon <ksolomon@gmail.com>
* @license Unlicense https://unlicense.org/
* @link https://github.com/ksolomon/Torn-Vault-Tracker
*/
class ApiValidationException extends Exception { class ApiValidationException extends Exception {
public function __construct($message, $code = 0, Throwable $previous = null) { /**
parent::__construct($message, $code, $previous); * Constructor.
} *
* @param string $message The exception message.
* @param int $code The exception code.
* @param Throwable $previous The previous throwable.
*/
public function __construct($message, $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
} }
+135 -96
View File
@@ -1,5 +1,21 @@
<?php <?php
/** Checks if the database is new and empty. /**
* Utility functions for the Torn Vault Tracker application.
*
* This file contains helper functions for database operations, API calls,
* and vault record management.
*
* PHP version 8.1+
*
* @category Utility
* @package TornVaultTracker
* @author Keith Solomon <ksolomon@gmail.com>
* @license Unlicense https://unlicense.org/
* @link https://github.com/ksolomon/Torn-Vault-Tracker
*/
/**
* Checks if the database is new and empty.
* *
* This function checks if the 'vault' table in the database has any entries. * This function checks if the 'vault' table in the database has any entries.
* If it does not, it returns true, indicating that the database is new and * If it does not, it returns true, indicating that the database is new and
@@ -8,25 +24,29 @@
* @return boolean True if the database is new and empty, false otherwise. * @return boolean True if the database is new and empty, false otherwise.
*/ */
function dbNew() { function dbNew() {
$pdo = getDatabaseConnection(); $pdo = getDatabaseConnection();
$stmt = $pdo->query("SELECT COUNT(*) FROM vault"); $stmt = $pdo->query("SELECT COUNT(*) FROM vault");
return $stmt->fetchColumn() == 0; return $stmt->fetchColumn() == 0;
} }
/** Ensures that a user has an API key configured. /**
* Ensures that a user has an API key configured.
* *
* @param string $user The user to check the API key for * @param string $user The user to check the API key for
* *
* @return void
*
* @throws Exception If the user does not have an API key configured * @throws Exception If the user does not have an API key configured
*/ */
function ensureUserHasApiKey($user) { function ensureUserHasApiKey($user) {
if (!array_key_exists($user, USER_KEYS)) { if (!array_key_exists($user, USER_KEYS)) {
throw new ApiKeyMissingException("User does not have an API key configured."); throw new ApiKeyMissingException("User does not have an API key configured.");
} }
} }
/** Executes a GET request to the given API endpoint and returns the JSON response as an associative array. /**
* Executes a GET request to the given API endpoint and returns the JSON response as an associative array.
* *
* @param string $apiEndpoint The URL of the API endpoint to call * @param string $apiEndpoint The URL of the API endpoint to call
* *
@@ -35,112 +55,125 @@ function ensureUserHasApiKey($user) {
* @return array The JSON response from the API * @return array The JSON response from the API
*/ */
function executeApiCall($apiEndpoint) { function executeApiCall($apiEndpoint) {
$headers = ["Content-Type: application/json"]; $headers = ["Content-Type: application/json"];
$ch = curl_init(); $ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiEndpoint); curl_setopt($ch, CURLOPT_URL, $apiEndpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch); $response = curl_exec($ch);
if (curl_errno($ch)) { if (curl_errno($ch)) {
throw new CurlErrorException("cURL error: " . curl_error($ch)); throw new CurlErrorException("cURL error: " . curl_error($ch));
} }
curl_close($ch); curl_close($ch);
$responseData = json_decode($response, true); $responseData = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) { if (json_last_error() !== JSON_ERROR_NONE) {
throw new JsonDataException("Failed to decode JSON response: " . json_last_error_msg()); throw new JsonDataException("Failed to decode JSON response: " . json_last_error_msg());
} }
return $responseData; return $responseData;
} }
/** Validates the API response data for the presence of a log array. /**
* Validates the API response data for the presence of a log array.
* *
* @param array $responseData The API response data to validate. * @param array $responseData The API response data to validate.
* *
* @return void
*
* @throws Exception If the log data is missing or not an array. * @throws Exception If the log data is missing or not an array.
*/ */
function validateApiResponse($responseData) { function validateApiResponse($responseData) {
if (!isset($responseData['log']) || !is_array($responseData['log'])) { if (!isset($responseData['log']) || !is_array($responseData['log'])) {
throw new ApiValidationException("Invalid log data received from the API."); throw new ApiValidationException("Invalid log data received from the API.");
} }
} }
/** Prepare a PDO statement for checking if a given vault transaction already exists in the database. /**
* Prepare a PDO statement for checking if a given vault transaction already exists in the database.
* *
* @param PDO $pdo The PDO instance to prepare the statement with * @param PDO $pdo The PDO instance to prepare the statement with
* *
* @return PDOStatement The prepared statement * @return PDOStatement The prepared statement
*/ */
function prepareCheckStatement($pdo) { function prepareCheckStatement($pdo) {
$checkQuery = "SELECT COUNT(*) FROM vault WHERE user = :user AND timestamp = :timestamp AND amount = :amount"; $checkQuery = "SELECT COUNT(*) FROM vault WHERE user = :user AND timestamp = :timestamp AND amount = :amount";
return $pdo->prepare($checkQuery); return $pdo->prepare($checkQuery);
} }
/** Prepare a PDO statement for inserting a new vault transaction into the database. /**
* Prepare a PDO statement for inserting a new vault transaction into the database.
* *
* @param PDO $pdo The PDO instance to prepare the statement with * @param PDO $pdo The PDO instance to prepare the statement with
* *
* @return PDOStatement The prepared statement * @return PDOStatement The prepared statement
*/ */
function prepareInsertStatement($pdo) { function prepareInsertStatement($pdo) {
$insertQuery = "INSERT INTO vault (ID, user, timestamp, description, amount) VALUES (:id, :user, :timestamp, :description, :amount)"; $insertQuery = "INSERT INTO vault (ID, user, timestamp, description, amount) VALUES (:id, :user, :timestamp, :description, :amount)";
return $pdo->prepare($insertQuery); return $pdo->prepare($insertQuery);
} }
/** Process an array of log entries retrieved from the Torn API. /**
* Process an array of log entries retrieved from the Torn API.
* *
* Goes through each log entry and checks if it's a vault deposit or withdrawal. * Goes through each log entry and checks if it's a vault deposit or withdrawal.
* If it is, it checks if the entry already exists in the database. If it * If it is, it checks if the entry already exists in the database. If it
* doesn't, it inserts the entry into the database. * doesn't, it inserts the entry into the database.
* *
* @param array $logEntries The array of log entries to process * @param array $logEntries The array of log entries to process
* @param string $user The user whose log entries are being processed * @param string $user The user whose log entries are being processed
* @param PDOStatement $checkStmt A prepared statement to check if an entry * @param PDOStatement $checkStmt A prepared statement to check if an entry
* already exists in the database * already exists in the database
* @param PDOStatement $insertStmt A prepared statement to insert a new entry * @param PDOStatement $insertStmt A prepared statement to insert a new entry
* into the database * into the database
* @param boolean $debug Whether to output debug information (default: false) * @param boolean $debug Whether to output debug information (default: false)
*
* @return void
*/ */
function processLogEntries($logEntries, $user, $checkStmt, $insertStmt, $debug) { function processLogEntries($logEntries, $user, $checkStmt, $insertStmt, $debug) {
foreach ($logEntries as $key =>$entry) { foreach ($logEntries as $key =>$entry) {
if ($debug) { if ($debug) {
$logMessage = "Raw entry:\n" . print_r($entry, true); $logMessage = "Raw entry:\n" . print_r($entry, true);
file_put_contents(__DIR__ . '/debug.log', $logMessage, FILE_APPEND); file_put_contents(__DIR__ . '/debug.log', $logMessage, FILE_APPEND);
}
$timestamp = $entry['timestamp'];
$description = $entry['title'];
$amount = $entry['log'] === 5850 ? $entry['data']['deposited'] : -$entry['data']['withdrawn'];
if ($debug) {
$logMessage = "Vault entry:\n\tUser: $user,\n\tTimestamp: $timestamp,\n\tDescription: $description,\n\tAmount: $amount\n";
file_put_contents(__DIR__ . '/debug.log', $logMessage, FILE_APPEND);
}
$checkStmt->execute(
[
':user' => $user,
':timestamp' => $timestamp,
':amount' => $amount
]
);
if ($checkStmt->fetchColumn() == 0) {
$insertStmt->execute(
[
':id' => $key,
':user' => $user,
':timestamp' => $timestamp,
':description' => $description,
':amount' => $amount
]
);
}
} }
$timestamp = $entry['timestamp'];
$description = $entry['title'];
$amount = $entry['log'] === 5850 ? $entry['data']['deposited'] : -$entry['data']['withdrawn'];
if ($debug) {
$logMessage = "Vault entry:\n\tUser: $user,\n\tTimestamp: $timestamp,\n\tDescription: $description,\n\tAmount: $amount\n";
file_put_contents(__DIR__ . '/debug.log', $logMessage, FILE_APPEND);
}
$checkStmt->execute([
':user' => $user,
':timestamp' => $timestamp,
':amount' => $amount
]);
if ($checkStmt->fetchColumn() == 0) {
$insertStmt->execute([
':id' => $key,
':user' => $user,
':timestamp' => $timestamp,
':description' => $description,
':amount' => $amount
]);
}
}
} }
/** Fetch vault records from the database /**
* Fetch vault records from the database
* If a user is provided, only that user's records * If a user is provided, only that user's records
* are returned. Otherwise, all records are returned. * are returned. Otherwise, all records are returned.
* *
@@ -149,29 +182,30 @@ function processLogEntries($logEntries, $user, $checkStmt, $insertStmt, $debug)
* @return array An array of records, or an empty array on error * @return array An array of records, or an empty array on error
*/ */
function fetchVaultRecords($user = null) { function fetchVaultRecords($user = null) {
$pdo = getDatabaseConnection(); $pdo = getDatabaseConnection();
if ($user) { if ($user) {
$query = "SELECT * FROM vault WHERE user = :user ORDER BY timestamp DESC"; $query = "SELECT * FROM vault WHERE user = :user ORDER BY timestamp DESC";
$params = [':user' => $user]; $params = [':user' => $user];
} else { } else {
$query = "SELECT * FROM vault ORDER BY timestamp DESC"; $query = "SELECT * FROM vault ORDER BY timestamp DESC";
$params = []; $params = [];
} }
try { try {
$stmt = $pdo->prepare($query); $stmt = $pdo->prepare($query);
$stmt->execute($params); $stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC); return $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) { } catch (PDOException $e) {
echo "Error fetching records: " . $e->getMessage(); echo "Error fetching records: " . $e->getMessage();
return []; return [];
} }
} }
/** Iterate over all vault records for the given user (or all users if no user is given), /**
* Iterate over all vault records for the given user (or all users if no user is given),
* *
* @param string|null $name (optional) The user to loop over records for. * @param string|null $name (optional) The user to loop over records for.
* If not provided, all users' records will be looped over. * If not provided, all users' records will be looped over.
@@ -179,15 +213,18 @@ function fetchVaultRecords($user = null) {
* @return int The total balance of the given user (or all users if no user is given). * @return int The total balance of the given user (or all users if no user is given).
*/ */
function vaultLoop ($name=null) { function vaultLoop ($name=null) {
$vault = fetchVaultRecords($name); $vault = fetchVaultRecords($name);
$balance = 0; $balance = 0;
foreach ($vault as $entry) { $balance += $entry['amount']; } foreach ($vault as $entry) {
$balance += $entry['amount'];
}
return $balance; return $balance;
} }
/** Returns a string indicating the sign of a number, with a dollar symbol. /**
* Returns a string indicating the sign of a number, with a dollar symbol.
* *
* @param int|float $number The number to check. * @param int|float $number The number to check.
* *
@@ -195,7 +232,9 @@ function vaultLoop ($name=null) {
* number is negative. * number is negative.
*/ */
function getSign($number) { function getSign($number) {
if (substr($number, 0, 1) == '-') { return '-$'; } if (substr($number, 0, 1) == '-') {
return '-$';
}
return '$'; return '$';
} }
+103 -92
View File
@@ -1,92 +1,103 @@
<?php <?php
require_once __DIR__ . '/config.php'; /**
include_once __DIR__ . '/functions.php'; * Main entry point for the Torn Vault Tracker application.
*
if (dbNew()) { * PHP version 8.1+
foreach (USER_KEYS as $key => $value) { *
firstRun($key); * @category Main
} * @package TornVaultTracker
header('Location: /'); * @author Keith Solomon <ksolmon@gmail.com>
} else { * @license Unlicense https://unlicense.org/
foreach (USER_KEYS as $key => $value) { * @link https://github.com/ksolmon/torn-vault-tracker
getLog($key); */
} require_once __DIR__ . '/config.php';
} require_once __DIR__ . '/functions.php';
?>
if (dbNew()) {
<!DOCTYPE html> foreach (USER_KEYS as $key => $value) {
<html lang="en"> firstRun($key);
}
<head> header('Location: /');
<meta charset="UTF-8"> } else {
<meta http-equiv="X-UA-Compatible" content="IE=edge"> foreach (USER_KEYS as $key => $value) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"> getLog($key);
<title>Torn Vault Tracker</title> }
<link rel="icon" type="image/png" href="favicon.png"> }
?>
<link rel="stylesheet" href="style.css?v=<?php echo filemtime('style.css'); ?>">
<!DOCTYPE html>
<link rel="preconnect" href="https://fonts.googleapis.com"> <html lang="en">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital@0;1&display=swap" rel="stylesheet"> <head>
</head> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<body> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<h1>Torn Vault Tracker</h1> <title>Torn Vault Tracker</title>
<link rel="icon" type="image/png" href="favicon.png">
<div class="grid">
<div class="gridLeft"> <link rel="stylesheet" href="style.css?v=<?php echo filemtime('style.css'); ?>">
<h1>Transactions</h1>
<link rel="preconnect" href="https://fonts.googleapis.com">
<table id="data"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<thead> <link href="https://fonts.googleapis.com/css2?family=Roboto:ital@0;1&display=swap" rel="stylesheet">
<tr> </head>
<th><h4>User</h4></th>
<th><h4>Date / Time (TCT)</h4></th> <body>
<th><h4>Operation</h4></th> <h1>Torn Vault Tracker</h1>
<th><h4>Amount</h4></th>
</tr> <div class="grid">
</thead> <div class="gridLeft">
<h1>Transactions</h1>
<tbody>
<?php buildTable(); ?> <table id="data">
</tbody> <thead>
</table> <tr>
<th><h4>User</h4></th>
<div id="pagination-controls"> <th><h4>Date / Time (TCT)</h4></th>
<button onclick="changePage(-999)">&laquo;</button> <th><h4>Operation</h4></th>
<button onclick="changePage(-1)">&lsaquo;</button> <th><h4>Amount</h4></th>
<div id="page-info">Page x of y</div> </tr>
<button onclick="changePage(1)">&rsaquo;</button> </thead>
<button onclick="changePage(999)">&raquo;</button>
</div> <tbody>
</div> <?php buildTable(); ?>
</tbody>
<div class="gridRight"> </table>
<h1>Balances</h1>
<div id="pagination-controls">
<section class="vault"> <button onclick="changePage(-999)">&laquo;</button>
<h2>Vault Balance: $<?php echo generateBalance(); ?></h2> <button onclick="changePage(-1)">&lsaquo;</button>
<h3>Space left: $<?php echo getSpace(); ?></h3> <div id="page-info">Page x of y</div>
</section> <button onclick="changePage(1)">&rsaquo;</button>
<button onclick="changePage(999)">&raquo;</button>
<h2>Shares</h2> </div>
<div class="grid"> </div>
<?php foreach (USER_KEYS as $key => $value) { ?>
<section class="user"> <div class="gridRight">
<h3><?php echo ucfirst($key); ?> balance: $<?php echo generateBalance($key); ?></h3> <h1>Balances</h1>
<h4>Share left: $<?php echo getSpace($key); ?></h4>
</section> <section class="vault">
<?php } ?> <h2>Vault Balance: $<?php echo generateBalance(); ?></h2>
</div> <h3>Space left: $<?php echo getSpace(); ?></h3>
</div> </section>
</div>
<h2>Shares</h2>
<script src="script.js"></script> <div class="grid">
<script> <?php foreach (USER_KEYS as $key => $value) { ?>
let rowsPerPage = <?php echo ROWS_PER_PAGE; ?>; // Set in config.php <section class="user">
<h3><?php echo ucfirst($key); ?> balance: $<?php echo generateBalance($key); ?></h3>
paginate(); <h4>Share left: $<?php echo getSpace($key); ?></h4>
</script> </section>
</body> <?php } ?>
</html> </div>
</div>
</div>
<script src="script.js"></script>
<script>
let rowsPerPage = <?php echo ROWS_PER_PAGE; ?>; // Set in config.php
paginate();
</script>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<ruleset name="Coding Style Checks">
<description>Coding Style Checks</description>
<ini name="error_reporting" value="E_ALL &#38; ~E_DEPRECATED" />
<arg value="sp"/>
<arg name="colors"/>
<arg name="extensions" value="php,html,css"/>
<arg name="parallel" value="2048"/>
<exclude-pattern>vendor/</exclude-pattern>
<exclude-pattern>node_modules/</exclude-pattern>
<rule ref="PEAR">
<exclude name="PEAR.Classes.ClassDeclaration"/>
<exclude name="PEAR.Functions.FunctionDeclaration"/>
<exclude name="Generic.Files.LineLength.TooLong"/>
<exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed"/>
<exclude name="Generic.Functions.CallTimePassByReference"/>
<exclude name="Squiz.Commenting.FileComment.MissingPackageTag"/>
<exclude name="Squiz.Commenting.FileComment.Missing"/>
<exclude name="Squiz.Commenting.FileComment.WrongStyle"/>
<exclude name="Squiz.Commenting.InlineComment.InvalidEndChar"/>
</rule>
<rule ref="Internal.NoCodeFound">
<severity>0</severity>
</rule>
</ruleset>
+60 -60
View File
@@ -1,60 +1,60 @@
:root { :root {
--red: #f77e82; --red: #f77e82;
--green: #08817d; --green: #08817d;
} }
body { body {
background: #000; background: #000;
color: #fff; color: #fff;
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
padding: 0 1em; padding: 0 1em;
} }
table { table {
color: #000; color: #000;
visibility: hidden; visibility: hidden;
width: 100%; width: 100%;
} }
table, tr, td, th { table, tr, td, th {
border: 1px solid #333; border: 1px solid #333;
border-collapse: collapse; border-collapse: collapse;
} }
thead th { thead th {
background: #ccc; background: #ccc;
color: #000; color: #000;
font-weight: bold; font-weight: bold;
padding: .15em 1em; padding: .15em 1em;
text-align: center; text-align: center;
text-transform: uppercase; text-transform: uppercase;
} }
tr.debit { background-color: var(--red); } tr.debit { background-color: var(--red); }
tr.credit { background-color: var(--green); color: #fff; } tr.credit { background-color: var(--green); color: #fff; }
td { padding: .15em 1em; } td { padding: .15em 1em; }
#pagination-controls { #pagination-controls {
align-items: center; align-items: center;
display: flex; display: flex;
justify-content: center; justify-content: center;
gap: 1em; gap: 1em;
margin: 1em 0; margin: 1em 0;
} }
h2, h3, h4 { margin: 0; } h2, h3, h4 { margin: 0; }
.grid { .grid {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
grid-template-rows: 1fr; grid-template-rows: 1fr;
grid-column-gap: 4em; grid-column-gap: 4em;
grid-row-gap: 0px; grid-row-gap: 0px;
margin-top: .5em; margin-top: .5em;
} }
.vault { margin: 0 0 3em; } .vault { margin: 0 0 3em; }
.vault h3, h4 { font-style: italic; } .vault h3, h4 { font-style: italic; }