From 3219ed335e3902c1e85284bb20343a9df9ef295c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 15:22:13 +0000 Subject: [PATCH 1/2] fix: billing DB safety, remove mapping table, sync services from game config Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/0b960e6d-bdf7-4b5b-8114-6c63e6b11a8d Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com> --- modules/billing/add_override_price_column.sql | 10 + .../add_remote_server_enabled_column.sql | 10 + modules/billing/adminserverlist.php | 415 ++++++++++-------- modules/billing/includes/config_loader.php | 48 +- modules/billing/module.php | 28 +- modules/billing/order.php | 52 ++- modules/billing/serverlist.php | 2 +- modules/billing/timestamp.txt | 2 +- 8 files changed, 332 insertions(+), 235 deletions(-) diff --git a/modules/billing/add_override_price_column.sql b/modules/billing/add_override_price_column.sql index 704a4418..565cc6d1 100644 --- a/modules/billing/add_override_price_column.sql +++ b/modules/billing/add_override_price_column.sql @@ -1,3 +1,13 @@ +-- DEPRECATED: This file is no longer needed. +-- +-- The gsp_billing_service_remote_servers mapping table has been removed. +-- Server availability per game/service is now stored in gsp_billing_services.remote_server_id +-- as a comma-separated list of numeric server IDs (e.g. "1,3,7"). +-- The module migration (db_version 4) drops the mapping table automatically. +-- +-- The original content of this file is kept below for historical reference only. +-- Do NOT run this script on new installations. +-- -- Migration: add override_price to billing_service_remote_servers -- Run once on existing installs that already have the mapping table (db_version 2) -- but are missing the override_price column (added in db_version 3 / module v3.1). diff --git a/modules/billing/add_remote_server_enabled_column.sql b/modules/billing/add_remote_server_enabled_column.sql index dc158104..b4726014 100644 --- a/modules/billing/add_remote_server_enabled_column.sql +++ b/modules/billing/add_remote_server_enabled_column.sql @@ -1,3 +1,13 @@ +-- DEPRECATED: This file is no longer needed. +-- +-- The billing module no longer references an `enabled` column on gsp_remote_servers. +-- gsp_remote_servers is the server inventory table only. +-- Server availability per game/service is stored in gsp_billing_services.remote_server_id +-- as a comma-separated list of numeric server IDs (e.g. "1,3,7"). +-- +-- The original content of this file is kept below for historical reference only. +-- Do NOT run this script on new installations. +-- -- Migration: add `enabled` column to gsp_remote_servers -- -- The original panel schema (panel.sql / ogp_remote_servers) includes an `enabled` diff --git a/modules/billing/adminserverlist.php b/modules/billing/adminserverlist.php index f3765e0c..5f944d1d 100644 --- a/modules/billing/adminserverlist.php +++ b/modules/billing/adminserverlist.php @@ -3,210 +3,258 @@ - Admin Server / Game Matrix - GameServers.World + Admin Service Configuration - GSP query( - "CREATE TABLE IF NOT EXISTS `{$table_prefix}billing_service_remote_servers` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `service_id` INT(11) NOT NULL, - `remote_server_id` INT(11) NOT NULL, - `enabled` TINYINT(1) NOT NULL DEFAULT 1, - `override_price` DECIMAL(10,2) NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `svc_rs` (`service_id`, `remote_server_id`), - KEY `service_id` (`service_id`), - KEY `remote_server_id` (`remote_server_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" -); -// Add override_price if this is an older install that already has the table without it -$chk = $db->query("SHOW COLUMNS FROM `{$table_prefix}billing_service_remote_servers` LIKE 'override_price'"); -if ($chk && $chk->num_rows === 0) { - $db->query("ALTER TABLE `{$table_prefix}billing_service_remote_servers` ADD COLUMN `override_price` DECIMAL(10,2) NULL"); +/* ----------------------------------------------------------------------- + Auto-sync: keep billing_services in step with game/mod config list + Runs on every page load; INSERT and soft-disable only — never hard-delete. +----------------------------------------------------------------------- */ +function sync_billing_services(mysqli $db, string $prefix): array +{ + $messages = []; + + // Load all games/mods from panel config tables + $gameMods = []; + $res = $db->query( + "SELECT cm.mod_cfg_id, cm.home_cfg_id, cm.mod_name, ch.game_name + FROM `{$prefix}config_mods` cm + JOIN `{$prefix}config_homes` ch ON ch.home_cfg_id = cm.home_cfg_id + ORDER BY ch.game_name, cm.mod_name" + ); + if ($res) { + while ($row = $res->fetch_assoc()) { + $gameMods[(int)$row['mod_cfg_id']] = $row; + } + } + + if (empty($gameMods)) { + // config_mods is empty or tables don't exist yet — nothing to sync + return $messages; + } + + // Load existing billing_services indexed by mod_cfg_id + $existing = []; + $svcRes = $db->query( + "SELECT service_id, mod_cfg_id, enabled, out_of_stock + FROM `{$prefix}billing_services`" + ); + if ($svcRes) { + while ($row = $svcRes->fetch_assoc()) { + $existing[(int)$row['mod_cfg_id']] = $row; + } + } + + // Insert new rows for game/mods not yet in billing_services + foreach ($gameMods as $modCfgId => $gm) { + if (isset($existing[$modCfgId])) { + continue; + } + $svcName = $db->real_escape_string($gm['mod_name'] ?: $gm['game_name']); + $homeCfgId = (int)$gm['home_cfg_id']; + $db->query( + "INSERT INTO `{$prefix}billing_services` + (home_cfg_id, mod_cfg_id, service_name, remote_server_id, + enabled, out_of_stock, price_daily, price_monthly, price_year, + slot_min_qty, slot_max_qty, install_method) + VALUES + ({$homeCfgId}, {$modCfgId}, '{$svcName}', '', + 0, 0, 0, 0, 0, + 1, 100, 'steamcmd')" + ); + $messages[] = "Added new service: " . ($gm['mod_name'] ?: $gm['game_name']); + } + + // Soft-disable billing_services whose mod_cfg_id no longer appears in config_mods + foreach ($existing as $modCfgId => $svcRow) { + if ($modCfgId > 0 && !isset($gameMods[$modCfgId])) { + $sid = (int)$svcRow['service_id']; + $db->query( + "UPDATE `{$prefix}billing_services` + SET enabled = 0, out_of_stock = 1 + WHERE service_id = {$sid} AND enabled = 1" + ); + if ($db->affected_rows > 0) { + $messages[] = "Service ID {$sid} disabled — game mod no longer in config."; + } + } + } + + return $messages; } -$flash = []; +$syncMessages = sync_billing_services($db, $table_prefix); + +$flash = []; $flashType = 'ok'; /* ----------------------------------------------------------------------- - SAVE: matrix form submitted + SAVE: service configuration form submitted ----------------------------------------------------------------------- */ -if (isset($_POST['save_matrix'])) { +if (isset($_POST['save_services'])) { + // Load valid remote server IDs for validation + $validServerIds = []; + $rsRes = $db->query("SELECT remote_server_id FROM `{$table_prefix}remote_servers`"); + while ($rsRes && ($rsRow = $rsRes->fetch_assoc())) { + $validServerIds[] = (int)$rsRow['remote_server_id']; + } + $validSet = array_flip($validServerIds); + $postedServices = $_POST['svc'] ?? []; - $postedMappings = $_POST['map'] ?? []; + $postedServers = $_POST['servers'] ?? []; foreach ((array)$postedServices as $sid => $svcData) { - $sid = (int)$sid; - $enabled = isset($svcData['enabled']) ? 1 : 0; - $base_price = number_format((float)($svcData['base_price'] ?? 0), 2, '.', ''); - $period = in_array($svcData['period'] ?? 'monthly', ['daily','monthly','yearly'], true) - ? $svcData['period'] : 'monthly'; + $sid = (int)$sid; + $enabled = isset($svcData['enabled']) ? 1 : 0; + $priceDaily = number_format((float)($svcData['price_daily'] ?? 0), 4, '.', ''); + $priceMonthly = number_format((float)($svcData['price_monthly'] ?? 0), 4, '.', ''); + $priceYear = number_format((float)($svcData['price_year'] ?? 0), 4, '.', ''); + $slotMin = max(0, (int)($svcData['slot_min_qty'] ?? 0)); + $slotMax = max(0, (int)($svcData['slot_max_qty'] ?? 0)); + if ($slotMax < $slotMin) { $slotMax = $slotMin; } - $price_col = $period === 'daily' ? 'price_daily' : ($period === 'yearly' ? 'price_year' : 'price_monthly'); - $base_esc = $db->real_escape_string($base_price); + // Build comma-separated remote_server_id from checkboxes, validating each ID + $checkedIds = []; + foreach ((array)($postedServers[$sid] ?? []) as $rawId) { + $rid = (int)$rawId; + if (isset($validSet[$rid])) { + $checkedIds[] = $rid; + } + } + $remoteServerIdStr = $db->real_escape_string(implode(',', $checkedIds)); $db->query( "UPDATE `{$table_prefix}billing_services` - SET enabled = {$enabled}, - `{$price_col}` = '{$base_esc}' + SET enabled = {$enabled}, + price_daily = '{$priceDaily}', + price_monthly = '{$priceMonthly}', + price_year = '{$priceYear}', + slot_min_qty = {$slotMin}, + slot_max_qty = {$slotMax}, + remote_server_id = '{$remoteServerIdStr}' WHERE service_id = {$sid}" ); } - // Upsert mappings: for every service x server pair post data received - $allServerIds = []; - $rsRes = $db->query("SELECT remote_server_id FROM `{$table_prefix}remote_servers`"); - while ($rsRes && ($rsRow = $rsRes->fetch_assoc())) { - $allServerIds[] = (int)$rsRow['remote_server_id']; - } - - $stmt = $db->prepare( - "INSERT INTO `{$table_prefix}billing_service_remote_servers` - (service_id, remote_server_id, enabled, override_price) - VALUES (?, ?, ?, ?) - ON DUPLICATE KEY UPDATE - enabled = VALUES(enabled), - override_price = VALUES(override_price)" - ); - foreach ((array)$postedServices as $sid => $ignored) { - $sid = (int)$sid; - foreach ($allServerIds as $rid) { - $mapEnabled = isset($postedMappings[$sid][$rid]['enabled']) ? 1 : 0; - $ovRaw = $postedMappings[$sid][$rid]['override_price'] ?? ''; - $ovPrice = (trim($ovRaw) === '') ? null : number_format((float)$ovRaw, 2, '.', ''); - if ($stmt) { - $stmt->bind_param('iisd', $sid, $rid, $mapEnabled, $ovPrice); - $stmt->execute(); - } - } - } - if ($stmt) { - $stmt->close(); - } - - $flash[] = "Matrix saved successfully."; + $flash[] = "Services saved."; } /* ----------------------------------------------------------------------- - Remove a service ------------------------------------------------------------------------ */ -if (isset($_POST['remove_service'], $_POST['service_id_remove'])) { - $sid = (int)$_POST['service_id_remove']; - $db->query("DELETE FROM `{$table_prefix}billing_service_remote_servers` WHERE service_id = {$sid}"); - $db->query("DELETE FROM `{$table_prefix}billing_services` WHERE service_id = {$sid}"); - $flash[] = "Service #{$sid} removed."; -} - -/* ----------------------------------------------------------------------- - Load data + Load data for display ----------------------------------------------------------------------- */ $remoteServers = []; -$rsRes = $db->query("SELECT remote_server_id, remote_server_name FROM `{$table_prefix}remote_servers` ORDER BY remote_server_name"); +$rsRes = $db->query( + "SELECT remote_server_id, remote_server_name + FROM `{$table_prefix}remote_servers` + ORDER BY remote_server_name" +); while ($rsRes && ($row = $rsRes->fetch_assoc())) { $remoteServers[] = $row; } $services = []; $svcRes = $db->query( - "SELECT service_id, service_name, enabled, price_daily, price_monthly, price_year + "SELECT service_id, service_name, enabled, price_daily, price_monthly, price_year, + slot_min_qty, slot_max_qty, remote_server_id FROM `{$table_prefix}billing_services` ORDER BY service_name" ); while ($svcRes && ($row = $svcRes->fetch_assoc())) { $services[] = $row; } - -// Load existing mappings into a lookup: $mappings[$service_id][$remote_server_id] = ['enabled'=>..,'override_price'=>..] -$mappings = []; -$mapRes = $db->query( - "SELECT service_id, remote_server_id, enabled, override_price - FROM `{$table_prefix}billing_service_remote_servers`" -); -while ($mapRes && ($row = $mapRes->fetch_assoc())) { - $mappings[(int)$row['service_id']][(int)$row['remote_server_id']] = [ - 'enabled' => (int)$row['enabled'], - 'override_price' => $row['override_price'], - ]; -} ?> - + $msg): + $type = ($flashType === 'err' || $idx < count((array)$syncMessages) && count($syncMessages) > 0 && strpos($msg, 'disabled') !== false) ? 'ok' : $flashType; +?>
-

Game × Server Matrix

+

Service Configuration

- Enable or disable each game for billing, set its base price and billing period, then - toggle availability per server and optionally override the price for that location. - Leave override blank to use the base price. + Enable services, configure pricing and slot ranges, and select which remote servers + each game can be installed on. The service list is automatically kept in sync with + the panel game/mod configuration. Check one or more servers to make a game available + for purchase; leaving all servers unchecked prevents the game from appearing in the + store.

-

No billing services found. Add services first via the database or the panel.

+

No billing services found. Ensure game configs are loaded in the panel (Home → Games configuration).

- +
- +
- + - - - - - + + + + + + 0) { - $basePrice = number_format((float)$svc['price_monthly'], 2, '.', ''); - $period = 'monthly'; - } elseif ((float)$svc['price_daily'] > 0) { - $basePrice = number_format((float)$svc['price_daily'], 2, '.', ''); - $period = 'daily'; - } elseif ((float)$svc['price_year'] > 0) { - $basePrice = number_format((float)$svc['price_year'], 2, '.', ''); - $period = 'yearly'; - } else { - $basePrice = '0.00'; - $period = 'monthly'; + + // Parse existing remote_server_id CSV into a set for fast checkbox lookup + $savedIds = []; + foreach (explode(',', (string)$svc['remote_server_id']) as $part) { + $part = trim($part); + if ($part !== '' && ctype_digit($part)) { + $savedIds[(int)$part] = true; + } } ?> @@ -215,44 +263,61 @@ while ($mapRes && ($row = $mapRes->fetch_assoc())) {
ID:
- - 0, 'override_price' => null]; - $mapEnabled = (int)$mapEntry['enabled']; - $ovPrice = $mapEntry['override_price']; - ?> - - + + + + + + + @@ -260,33 +325,25 @@ while ($mapRes && ($row = $mapRes->fetch_assoc())) {
- +
-

Remove a Service

- - - - - - -
-

Legend: Checkbox = server is available for this game. - Override price = customer pays this amount instead of the base price for that location. - Leave override blank to use the game base price.

-

- Availability is controlled entirely by . - No entry or enabled = 0 means the server is not offered for that game. -

+
+

Notes:

+
    +
  • A service will only appear in the store when Enabled is checked + and at least one server is selected.
  • +
  • Available servers are stored as a comma-separated list of server IDs in + .
  • +
  • The service list is automatically synced with the panel game/mod configuration on + every page load. New games are added with Enabled = off so they do not + appear in the store until you configure and enable them.
  • +
  • Games removed from the panel configuration are disabled automatically; they are + never deleted while orders may reference them.
  • +
diff --git a/modules/billing/includes/config_loader.php b/modules/billing/includes/config_loader.php index 6f445ba5..3ee9f533 100644 --- a/modules/billing/includes/config_loader.php +++ b/modules/billing/includes/config_loader.php @@ -2,36 +2,25 @@ /** * Billing config loader * - * Priority order (standalone-first): - * 1. modules/billing/includes/config.inc.php (local billing config — always wins when present) - * 2. /includes/config.inc.php (panel config — fallback when no local config) + * Priority order (panel-first): + * 1. /includes/config.inc.php (active panel config — always wins when present) + * 2. modules/billing/includes/config.inc.php (local billing config — standalone fallback only) * - * This ensures that copying modules/billing/ to any web root works correctly - * after editing its own config.inc.php, without being overridden by a parent - * panel installation that may have a different database name. + * The panel config is preferred so that every billing page, migration, and schema + * check automatically uses the database from the active installation. This prevents + * a testing install from accidentally writing to a production database when the local + * billing config.inc.php still contains hard-coded production credentials. + * + * Standalone deployments (billing module deployed without the panel) should place + * their own config.inc.php in modules/billing/includes/ as a fallback. */ if (defined('BILLING_CONFIG_LOADED')) { return; } -$localConfig = __DIR__ . '/config.inc.php'; $attempted = []; -// Always prefer the local billing config so the module is self-contained. -if (is_readable($localConfig)) { - $attempted[] = $localConfig; - require_once $localConfig; - if (!defined('BILLING_CONFIG_PATH')) { - define('BILLING_CONFIG_PATH', $localConfig); - } - define('BILLING_CONFIG_LOADED', true); - return; -} - -$attempted[] = $localConfig; - -// Fallback: try to load the panel's config (useful when running embedded inside the panel -// and no local copy has been made yet). +// Prefer the panel config so the billing module always uses the active installation's DB. $panelConfig = null; $projectRoot = realpath(__DIR__ . '/../../..'); if ($projectRoot !== false) { @@ -52,6 +41,21 @@ if ($panelConfig && is_readable($panelConfig)) { $attempted[] = $panelConfig; +// Fallback: local billing config (useful for standalone deployments where no panel is present). +$localConfig = __DIR__ . '/config.inc.php'; + +if (is_readable($localConfig)) { + $attempted[] = $localConfig; + require_once $localConfig; + if (!defined('BILLING_CONFIG_PATH')) { + define('BILLING_CONFIG_PATH', $localConfig); + } + define('BILLING_CONFIG_LOADED', true); + return; +} + +$attempted[] = $localConfig; + $message = "GSP Billing module cannot find config.inc.php.\n"; $message .= "Looked in:\n"; foreach ((array)$attempted as $path) { diff --git a/modules/billing/module.php b/modules/billing/module.php index f310acbf..7b84143d 100644 --- a/modules/billing/module.php +++ b/modules/billing/module.php @@ -24,8 +24,8 @@ // Module general information $module_title = "billing"; -$module_version = "3.1"; -$db_version = 3; +$module_version = "3.2"; +$db_version = 4; $module_required = FALSE; // Module description $module_description = "Billing storefront / provisioning integration. Public ordering runs as a standalone site; panel pages provide provisioning and admin order management."; @@ -44,25 +44,26 @@ $install_queries[0] = array( // Billing Services - Available game server packages "CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."billing_services` ( `service_id` INT(11) NOT NULL AUTO_INCREMENT, - `home_cfg_id` INT(11) NOT NULL, - `mod_cfg_id` INT(11) NOT NULL, + `home_cfg_id` INT(11) NOT NULL DEFAULT 0, + `mod_cfg_id` INT(11) NOT NULL DEFAULT 0, `service_name` VARCHAR(255) NOT NULL, - `remote_server_id` VARCHAR(255) NOT NULL, + `remote_server_id` VARCHAR(255) NOT NULL DEFAULT '', `out_of_stock` VARCHAR(255) NOT NULL DEFAULT '', - `slot_max_qty` INT(11) NOT NULL, - `slot_min_qty` INT(11) NOT NULL, + `slot_max_qty` INT(11) NOT NULL DEFAULT 0, + `slot_min_qty` INT(11) NOT NULL DEFAULT 0, `price_daily` FLOAT(15,4) NOT NULL DEFAULT 0, `price_monthly` FLOAT(15,4) NOT NULL DEFAULT 0, `price_year` FLOAT(15,4) NOT NULL DEFAULT 0, `description` VARCHAR(1000) NOT NULL DEFAULT '', `img_url` VARCHAR(255) NOT NULL DEFAULT '', `ftp` VARCHAR(255) NOT NULL DEFAULT '', - `install_method` VARCHAR(255) NOT NULL DEFAULT '', + `install_method` VARCHAR(255) NOT NULL DEFAULT 'steamcmd', `manual_url` VARCHAR(255) NOT NULL DEFAULT '', `access_rights` VARCHAR(255) NOT NULL DEFAULT '', - `enabled` INT(11) NOT NULL DEFAULT 1, + `enabled` INT(11) NOT NULL DEFAULT 0, PRIMARY KEY (`service_id`), - KEY `enabled` (`enabled`) + KEY `enabled` (`enabled`), + KEY `mod_cfg_id` (`mod_cfg_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;", // Billing Orders - Actual game server instances (ongoing services) @@ -179,4 +180,11 @@ $install_queries[2] = array( "ALTER TABLE `".OGP_DB_PREFIX."billing_service_remote_servers` ADD COLUMN `override_price` DECIMAL(10,2) NULL AFTER `enabled`" ); +// Version 4 (array index 3): Remove the separate service-to-server mapping table. +// remote_server_id on billing_services now stores a comma-separated list of server IDs. +// The mapping table is no longer used; drop it if it still exists from older installs. +$install_queries[3] = array( + "DROP TABLE IF EXISTS `".OGP_DB_PREFIX."billing_service_remote_servers`" +); + ?> diff --git a/modules/billing/order.php b/modules/billing/order.php index 6a662eb0..fabaa410 100644 --- a/modules/billing/order.php +++ b/modules/billing/order.php @@ -189,29 +189,37 @@ if ($row['price_monthly'] == 0.0) {
GameGame / Service EnabledBase Price ($)Period
- # -
Price / Day ($)Price / Month ($)Price / Year ($)Min SlotsMax SlotsAvailable Servers
+ > - + - + - - > -
- -
+ + + + + + + + No remote servers configured + + + + + +
Location query($mappedQuery); - if ($mappedResult) { - $firstServer = true; - while ($rs = $mappedResult->fetch_assoc()) { - $rsID = (int)$rs['remote_server_id']; - $rsNAME = htmlspecialchars((string)$rs['remote_server_name'], ENT_QUOTES, 'UTF-8'); - $checked = $firstServer ? ' checked' : ''; - $available_server = true; - $firstServer = false; - echo "
\n" - . " \n" - . " \n" - . "
\n"; + $remoteIdsCsv = (string)($row['remote_server_id'] ?? ''); + $allowedIds = []; + foreach (explode(',', $remoteIdsCsv) as $part) { + $part = trim($part); + if ($part !== '' && ctype_digit($part)) { + $allowedIds[] = (int)$part; + } + } + if (!empty($allowedIds)) { + $inList = implode(',', $allowedIds); + $rsQuery = "SELECT remote_server_id, remote_server_name + FROM {$table_prefix}remote_servers + WHERE remote_server_id IN ({$inList}) + ORDER BY remote_server_name"; + $rsResult = $db->query($rsQuery); + if ($rsResult) { + $firstServer = true; + while ($rs = $rsResult->fetch_assoc()) { + $rsID = (int)$rs['remote_server_id']; + $rsNAME = htmlspecialchars((string)$rs['remote_server_name'], ENT_QUOTES, 'UTF-8'); + $checked = $firstServer ? ' checked' : ''; + $available_server = true; + $firstServer = false; + echo "
\n" + . " \n" + . " \n" + . "
\n"; + } } } ?> diff --git a/modules/billing/serverlist.php b/modules/billing/serverlist.php index 8962d33f..92095542 100644 --- a/modules/billing/serverlist.php +++ b/modules/billing/serverlist.php @@ -39,7 +39,7 @@ if (isset($_POST['save']) && !empty($_POST['description'])) { // Fetch services $service_id = isset($_REQUEST['service_id']) ? intval($_REQUEST['service_id']) : 0; -$where_service_id = $service_id !== 0 ? "WHERE enabled = 1 AND service_id = $service_id" : "WHERE enabled = 1"; +$where_service_id = $service_id !== 0 ? "WHERE enabled = 1 AND service_id = $service_id AND remote_server_id != ''" : "WHERE enabled = 1 AND remote_server_id != ''"; $qry_services = "SELECT * FROM {$table_prefix}billing_services $where_service_id ORDER BY service_name"; $services = $db->query($qry_services); diff --git a/modules/billing/timestamp.txt b/modules/billing/timestamp.txt index 4fdf6d43..c740e878 100644 --- a/modules/billing/timestamp.txt +++ b/modules/billing/timestamp.txt @@ -1 +1 @@ -Last Updated at 1:15pm on 2026-02-05 +Last Updated at 3:21pm on 2026-02-05 From 8a832b0eacf8cdf6181ad84eb2622ffd64083497 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 15:22:58 +0000 Subject: [PATCH 2/2] fix: remove unused $type variable in adminserverlist.php flash loop Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/0b960e6d-bdf7-4b5b-8114-6c63e6b11a8d Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com> --- modules/billing/adminserverlist.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/billing/adminserverlist.php b/modules/billing/adminserverlist.php index 5f944d1d..eb1a1f1e 100644 --- a/modules/billing/adminserverlist.php +++ b/modules/billing/adminserverlist.php @@ -207,9 +207,7 @@ while ($svcRes && ($row = $svcRes->fetch_assoc())) { } ?> - $msg): - $type = ($flashType === 'err' || $idx < count((array)$syncMessages) && count($syncMessages) > 0 && strpos($msg, 'disabled') !== false) ? 'ok' : $flashType; -?> +