From 60bcc67056581bd83e5141e2eedf23ce690681f2 Mon Sep 17 00:00:00 2001 From: Frank Harris Date: Wed, 17 Jun 2026 15:50:59 -0500 Subject: [PATCH] 'rebuilt missing sales and staff pages --- Panel/modules/website/README.md | 60 +- Panel/modules/website/admin.php | 8 + Panel/modules/website/api/capture_order.php | 80 ++ Panel/modules/website/api/create_order.php | 97 ++ Panel/modules/website/cart.php | 26 +- Panel/modules/website/checkout.php | 46 + Panel/modules/website/forgot_password.php | 54 + Panel/modules/website/includes/billing.php | 538 +++++++++ Panel/modules/website/includes/bootstrap.php | 44 +- Panel/modules/website/includes/footer.php | 6 +- Panel/modules/website/includes/navigation.php | 8 +- Panel/modules/website/invoices.php | 5 + Panel/modules/website/login.php | 4 + Panel/modules/website/my_servers.php | 15 + Panel/modules/website/order.php | 7 +- Panel/modules/website/orders.php | 5 + Panel/modules/website/pages/cart.php | 6 +- Panel/modules/website/pages/checkout.php | 50 + .../modules/website/pages/forgot_password.php | 12 + Panel/modules/website/pages/invoices.php | 7 + Panel/modules/website/pages/login.php | 2 + Panel/modules/website/pages/message.php | 19 + Panel/modules/website/pages/my_servers.php | 54 + Panel/modules/website/pages/order.php | 6 +- Panel/modules/website/pages/orders.php | 7 + Panel/modules/website/pages/register.php | 28 + .../modules/website/pages/reset_password.php | 19 + Panel/modules/website/pages/staff.php | 18 + Panel/modules/website/pages/staff_coupons.php | 7 + .../modules/website/pages/staff_invoices.php | 2 + .../modules/website/pages/staff_locations.php | 45 + .../website/pages/staff_migrations.php | 7 + Panel/modules/website/pages/staff_orders.php | 2 + .../modules/website/pages/staff_payments.php | 2 + Panel/modules/website/pages/staff_paypal.php | 15 + .../website/pages/staff_provisioning.php | 2 + .../modules/website/pages/staff_services.php | 18 + .../modules/website/pages/staff_settings.php | 33 + Panel/modules/website/payment_cancel.php | 4 + Panel/modules/website/payment_success.php | 4 + Panel/modules/website/register.php | 80 ++ Panel/modules/website/reset_password.php | 64 + Panel/modules/website/staff.php | 5 + Panel/modules/website/staff_coupons.php | 7 + Panel/modules/website/staff_invoices.php | 2 + Panel/modules/website/staff_locations.php | 14 + Panel/modules/website/staff_migrations.php | 10 + Panel/modules/website/staff_orders.php | 2 + Panel/modules/website/staff_payments.php | 2 + Panel/modules/website/staff_paypal.php | 20 + Panel/modules/website/staff_provisioning.php | 2 + Panel/modules/website/staff_services.php | 20 + Panel/modules/website/staff_settings.php | 12 + Panel/modules/website/webhook.php | 81 ++ backup-website/.htaccess | 1 + backup-website/BILLING_FIX_SUMMARY.md | 242 ++++ backup-website/COLUMN_RENAME_SUMMARY.md | 110 ++ backup-website/COUPON_SYSTEM.md | 364 ++++++ backup-website/FIXES_APPLIED.md | 247 ++++ backup-website/INVOICE_FIRST_FLOW.md | 190 +++ backup-website/INVOICE_SYSTEM.md | 133 +++ backup-website/LOGGING_CHANGES_SUMMARY.md | 223 ++++ backup-website/MIGRATION_SUMMARY.md | 201 ++++ .../PAYMENT_IMPLEMENTATION_SUMMARY.md | 282 +++++ backup-website/PAYPAL_DEBUGGING_GUIDE.md | 316 +++++ backup-website/QUICK_DEBUG_REFERENCE.md | 186 +++ backup-website/README_COUPON_UPDATE.md | 287 +++++ backup-website/RECENT_FIXES_SUMMARY.md | 266 +++++ backup-website/STATUS_REPORT.md | 176 +++ backup-website/TESTING_CHECKLIST.md | 339 ++++++ backup-website/_archived/CONFIGURATION.md | 165 +++ backup-website/_archived/FEATURES.md | 383 ++++++ .../_archived/IMPLEMENTATION_SUMMARY.md | 180 +++ backup-website/_archived/README_LOGIN.md | 109 ++ backup-website/_archived/VISUAL_GUIDE.md | 317 +++++ .../ARCHIVE_README.txt | 16 + .../removed-20251023-142000/MOVED_DOCS.md | 3 + .../removed-20251023-202500/MOVED_FILES.json | 75 ++ .../_archived/removed-20251023-202500/ai.php | 325 +++++ .../data/FREE-548-1761171178.json | 12 + .../data/FREE-549-1761246925.json | 12 + .../data/INV-20250825-170438-e37518.json | 11 + .../data/INV-20250825-174311-0a7993.json | 11 + .../data/NO-INVOICE.json | 10 + .../SIMULATED-WEBHOOK-20251022-101500.json | 10 + backup-website/add_paypal_data_column.sql | 10 + backup-website/add_service_id_column.sql | 10 + backup-website/add_to_cart.php | 200 ++++ backup-website/admin.php | 69 ++ backup-website/admin_config.php | 103 ++ backup-website/admin_coupons.php | 446 +++++++ backup-website/admin_invoices.php | 166 +++ backup-website/admin_payments.php | 59 + backup-website/adminserverlist.php | 338 ++++++ backup-website/ai.php | 326 +++++ backup-website/api/capture_order.php | 305 +++++ backup-website/api/create_order.php | 266 +++++ backup-website/api/error_log | 1 + backup-website/api/log_error.php | 44 + backup-website/bootstrap.php | 114 ++ backup-website/cart.php | 762 ++++++++++++ backup-website/check_table.php | 76 ++ backup-website/cleanupDB.sh | 3 + backup-website/create_coupons_table.sql | 107 ++ backup-website/create_invoices_table.sql | 34 + backup-website/create_servers.php | 376 ++++++ backup-website/cron-shop.php | 481 ++++++++ backup-website/css/header.css | 382 ++++++ backup-website/data/debug_cart.log | 1 + backup-website/diag_remote.php | 72 ++ backup-website/docs.php | 417 +++++++ backup-website/docs/7daystodie/icon.jpg | Bin 0 -> 40986 bytes backup-website/docs/7daystodie/index.php | 68 ++ backup-website/docs/7daystodie/metadata.json | 6 + .../docs/DOCUMENTATION_ENHANCEMENT_SUMMARY.md | 249 ++++ .../docs/DOCUMENTATION_EXPANSION_PLAN.md | 271 +++++ ...sting Reference (Multiplayer PC Games).pdf | Bin 0 -> 135853 bytes backup-website/docs/README.md | 160 +++ backup-website/docs/aliensvspredator/icon.png | Bin 0 -> 2869 bytes .../docs/aliensvspredator/index.php | 66 ++ .../docs/aliensvspredator/metadata.json | 6 + backup-website/docs/aoc/icon.png | Bin 0 -> 3622 bytes backup-website/docs/aoc/index.php | 66 ++ backup-website/docs/aoc/metadata.json | 6 + backup-website/docs/arkse/icon.jpg | Bin 0 -> 133659 bytes backup-website/docs/arkse/index.php | 304 +++++ backup-website/docs/arkse/metadata.json | 6 + backup-website/docs/arma-reforger/icon.png | Bin 0 -> 3266 bytes backup-website/docs/arma-reforger/index.php | 68 ++ .../docs/arma-reforger/metadata.json | 6 + backup-website/docs/arma2co/icon.png | Bin 0 -> 3010 bytes backup-website/docs/arma2co/index.php | 68 ++ backup-website/docs/arma2co/metadata.json | 6 + backup-website/docs/arma2oa/icon.jpg | Bin 0 -> 40955 bytes backup-website/docs/arma2oa/index.php | 68 ++ backup-website/docs/arma2oa/metadata.json | 6 + backup-website/docs/arma3/icon.jpg | Bin 0 -> 33192 bytes backup-website/docs/arma3/index.php | 68 ++ backup-website/docs/arma3/metadata.json | 6 + backup-website/docs/assettocorsa/icon.png | Bin 0 -> 3168 bytes backup-website/docs/assettocorsa/index.php | 68 ++ .../docs/assettocorsa/metadata.json | 6 + backup-website/docs/atlas/icon.png | Bin 0 -> 2490 bytes backup-website/docs/atlas/index.php | 68 ++ backup-website/docs/atlas/metadata.json | 6 + backup-website/docs/avorion/icon.jpg | Bin 0 -> 32342 bytes backup-website/docs/avorion/index.php | 68 ++ backup-website/docs/avorion/metadata.json | 6 + backup-website/docs/bec/icon.jpg | Bin 0 -> 71176 bytes backup-website/docs/bec/index.php | 66 ++ backup-website/docs/bec/metadata.json | 6 + backup-website/docs/bf2/icon.png | Bin 0 -> 2772 bytes backup-website/docs/bf2/index.php | 68 ++ backup-website/docs/bf2/metadata.json | 6 + backup-website/docs/bfbc2/icon.png | Bin 0 -> 2618 bytes backup-website/docs/bfbc2/index.php | 68 ++ backup-website/docs/bfbc2/metadata.json | 6 + backup-website/docs/bigbrotherbot/icon.png | Bin 0 -> 2766 bytes backup-website/docs/bigbrotherbot/index.php | 66 ++ .../docs/bigbrotherbot/metadata.json | 6 + backup-website/docs/bloodfrontier/icon.png | Bin 0 -> 2702 bytes backup-website/docs/bloodfrontier/index.php | 66 ++ .../docs/bloodfrontier/metadata.json | 6 + backup-website/docs/brainbread2/icon.jpg | Bin 0 -> 175402 bytes backup-website/docs/brainbread2/index.php | 68 ++ backup-website/docs/brainbread2/metadata.json | 6 + backup-website/docs/callofduty/icon.png | Bin 0 -> 3229 bytes backup-website/docs/callofduty/index.php | 68 ++ backup-website/docs/callofduty/metadata.json | 6 + backup-website/docs/callofduty2/icon.png | Bin 0 -> 3400 bytes backup-website/docs/callofduty2/index.php | 68 ++ backup-website/docs/callofduty2/metadata.json | 6 + backup-website/docs/callofduty4mw/icon.png | Bin 0 -> 3245 bytes backup-website/docs/callofduty4mw/index.php | 68 ++ .../docs/callofduty4mw/metadata.json | 6 + backup-website/docs/callofdutymw2/icon.png | Bin 0 -> 3245 bytes backup-website/docs/callofdutymw2/index.php | 68 ++ .../docs/callofdutymw2/metadata.json | 6 + backup-website/docs/callofdutymw3/icon.png | Bin 0 -> 3245 bytes backup-website/docs/callofdutymw3/index.php | 68 ++ .../docs/callofdutymw3/metadata.json | 6 + backup-website/docs/callofdutyuo/icon.png | Bin 0 -> 3245 bytes backup-website/docs/callofdutyuo/index.php | 68 ++ .../docs/callofdutyuo/metadata.json | 6 + backup-website/docs/callofdutywaw/icon.png | Bin 0 -> 3245 bytes backup-website/docs/callofdutywaw/index.php | 68 ++ .../docs/callofdutywaw/metadata.json | 6 + backup-website/docs/citadelfwf/icon.png | Bin 0 -> 3121 bytes backup-website/docs/citadelfwf/index.php | 66 ++ backup-website/docs/citadelfwf/metadata.json | 6 + backup-website/docs/cod_blackops/icon.png | Bin 0 -> 3732 bytes backup-website/docs/cod_blackops/index.php | 68 ++ .../docs/cod_blackops/metadata.json | 6 + backup-website/docs/colonysurvival/icon.jpg | Bin 0 -> 47610 bytes backup-website/docs/colonysurvival/index.php | 68 ++ .../docs/colonysurvival/metadata.json | 6 + backup-website/docs/common-issues/icon.png | Bin 0 -> 70 bytes backup-website/docs/common-issues/index.php | 128 ++ .../docs/common-issues/metadata.json | 6 + backup-website/docs/conanexiles/icon.jpg | Bin 0 -> 37168 bytes backup-website/docs/conanexiles/index.php | 68 ++ backup-website/docs/conanexiles/metadata.json | 6 + backup-website/docs/cs2d/icon.png | Bin 0 -> 2802 bytes backup-website/docs/cs2d/index.php | 66 ++ backup-website/docs/cs2d/metadata.json | 6 + backup-website/docs/csgo/icon.png | Bin 0 -> 3168 bytes backup-website/docs/csgo/index.php | 584 +++++++++ backup-website/docs/csgo/index_old.php | 67 ++ backup-website/docs/csgo/metadata.json | 6 + backup-website/docs/cspromod/icon.png | Bin 0 -> 3081 bytes backup-website/docs/cspromod/index.php | 68 ++ backup-website/docs/cspromod/metadata.json | 6 + backup-website/docs/css/icon.jpg | Bin 0 -> 2126 bytes backup-website/docs/css/index.php | 68 ++ backup-website/docs/css/metadata.json | 6 + backup-website/docs/cstrike/icon.jpg | Bin 0 -> 28138 bytes backup-website/docs/cstrike/index.php | 68 ++ backup-website/docs/cstrike/metadata.json | 6 + backup-website/docs/czero/icon.png | Bin 0 -> 3196 bytes backup-website/docs/czero/index.php | 68 ++ backup-website/docs/czero/metadata.json | 6 + backup-website/docs/dayz/icon.png | Bin 0 -> 2483 bytes backup-website/docs/dayz/index.php | 68 ++ backup-website/docs/dayz/metadata.json | 6 + backup-website/docs/dayzmod/icon.jpg | Bin 0 -> 37224 bytes backup-website/docs/dayzmod/index.php | 68 ++ backup-website/docs/dayzmod/metadata.json | 6 + backup-website/docs/dmc/icon.jpg | Bin 0 -> 2269 bytes backup-website/docs/dmc/index.php | 66 ++ backup-website/docs/dmc/metadata.json | 6 + backup-website/docs/dod/icon.png | Bin 0 -> 2917 bytes backup-website/docs/dod/index.php | 68 ++ backup-website/docs/dod/metadata.json | 6 + backup-website/docs/dods/icon.jpg | Bin 0 -> 25387 bytes backup-website/docs/dods/index.php | 68 ++ backup-website/docs/dods/metadata.json | 6 + backup-website/docs/doi/icon.jpg | Bin 0 -> 1920 bytes backup-website/docs/doi/index.php | 68 ++ backup-website/docs/doi/metadata.json | 6 + .../docs/dontstarvetogether/icon.png | Bin 0 -> 3062 bytes .../docs/dontstarvetogether/index.php | 68 ++ .../docs/dontstarvetogether/metadata.json | 6 + backup-website/docs/dystopia/icon.png | Bin 0 -> 2909 bytes backup-website/docs/dystopia/index.php | 68 ++ backup-website/docs/dystopia/metadata.json | 6 + backup-website/docs/eco/icon.jpg | Bin 0 -> 44396 bytes backup-website/docs/eco/index.php | 68 ++ backup-website/docs/eco/metadata.json | 6 + backup-website/docs/empyriongs/icon.png | Bin 0 -> 1813 bytes backup-website/docs/empyriongs/index.php | 68 ++ backup-website/docs/empyriongs/metadata.json | 6 + backup-website/docs/enemyterritory/icon.png | Bin 0 -> 3474 bytes backup-website/docs/enemyterritory/index.php | 68 ++ .../docs/enemyterritory/metadata.json | 6 + backup-website/docs/epochmod/icon.png | Bin 0 -> 3384 bytes backup-website/docs/epochmod/index.php | 68 ++ backup-website/docs/epochmod/metadata.json | 6 + backup-website/docs/esmod/icon.png | Bin 0 -> 1996 bytes backup-website/docs/esmod/index.php | 66 ++ backup-website/docs/esmod/metadata.json | 6 + backup-website/docs/ets2/icon.png | Bin 0 -> 1920 bytes backup-website/docs/ets2/index.php | 68 ++ backup-website/docs/ets2/metadata.json | 6 + backup-website/docs/factorio/icon.jpg | Bin 0 -> 69468 bytes backup-website/docs/factorio/index.php | 68 ++ backup-website/docs/factorio/metadata.json | 6 + backup-website/docs/feedthebeast/icon.png | Bin 0 -> 1774 bytes backup-website/docs/feedthebeast/index.php | 68 ++ .../docs/feedthebeast/metadata.json | 6 + backup-website/docs/fgms/icon.png | Bin 0 -> 2182 bytes backup-website/docs/fgms/index.php | 66 ++ backup-website/docs/fgms/metadata.json | 6 + backup-website/docs/fivem/icon.png | Bin 0 -> 1495 bytes backup-website/docs/fivem/index.php | 68 ++ backup-website/docs/fivem/metadata.json | 6 + backup-website/docs/fof/icon.jpg | Bin 0 -> 52615 bytes backup-website/docs/fof/index.php | 68 ++ backup-website/docs/fof/metadata.json | 6 + backup-website/docs/freecol/icon.png | Bin 0 -> 1583 bytes backup-website/docs/freecol/index.php | 66 ++ backup-website/docs/freecol/metadata.json | 6 + .../docs/gameserver_catalog_all_sources.yaml | 1052 +++++++++++++++++ .../docs/gameserver_catalog_lgsm_full.yaml | 432 +++++++ .../docs/gameserver_knowledgepack_v2.yaml | 692 +++++++++++ backup-website/docs/garrysmod/icon.jpg | Bin 0 -> 20463 bytes backup-website/docs/garrysmod/index.php | 68 ++ backup-website/docs/garrysmod/metadata.json | 6 + backup-website/docs/gearbox/icon.png | Bin 0 -> 3231 bytes backup-website/docs/gearbox/index.php | 66 ++ backup-website/docs/gearbox/metadata.json | 6 + backup-website/docs/getting-started/icon.png | Bin 0 -> 70 bytes backup-website/docs/getting-started/index.php | 93 ++ .../docs/getting-started/metadata.json | 6 + backup-website/docs/halo_ce/icon.png | Bin 0 -> 1536 bytes backup-website/docs/halo_ce/index.php | 66 ++ backup-website/docs/halo_ce/metadata.json | 6 + backup-website/docs/harsh/icon.jpg | Bin 0 -> 39125 bytes backup-website/docs/harsh/index.php | 66 ++ backup-website/docs/harsh/metadata.json | 6 + backup-website/docs/hidden_source/icon.png | Bin 0 -> 2151 bytes backup-website/docs/hidden_source/index.php | 68 ++ .../docs/hidden_source/metadata.json | 6 + backup-website/docs/hl2d/icon.png | Bin 0 -> 1692 bytes backup-website/docs/hl2d/index.php | 68 ++ backup-website/docs/hl2d/metadata.json | 6 + backup-website/docs/hldm/icon.png | Bin 0 -> 1679 bytes backup-website/docs/hldm/index.php | 68 ++ backup-website/docs/hldm/metadata.json | 6 + backup-website/docs/hltv/icon.png | Bin 0 -> 1199 bytes backup-website/docs/hltv/index.php | 66 ++ backup-website/docs/hltv/metadata.json | 6 + backup-website/docs/homefront/icon.png | Bin 0 -> 1779 bytes backup-website/docs/homefront/index.php | 66 ++ backup-website/docs/homefront/metadata.json | 6 + backup-website/docs/hurtworld/icon.jpg | Bin 0 -> 2645 bytes backup-website/docs/hurtworld/index.php | 68 ++ backup-website/docs/hurtworld/metadata.json | 6 + backup-website/docs/il2/icon.png | Bin 0 -> 2184 bytes backup-website/docs/il2/index.php | 66 ++ backup-website/docs/il2/metadata.json | 6 + backup-website/docs/ins/icon.jpg | Bin 0 -> 34600 bytes backup-website/docs/ins/index.php | 68 ++ backup-website/docs/ins/metadata.json | 6 + backup-website/docs/insurgencymic/icon.png | Bin 0 -> 2107 bytes backup-website/docs/insurgencymic/index.php | 68 ++ .../docs/insurgencymic/metadata.json | 6 + .../docs/insurgencysandstorm/icon.png | Bin 0 -> 2107 bytes .../docs/insurgencysandstorm/index.php | 68 ++ .../docs/insurgencysandstorm/metadata.json | 6 + backup-website/docs/ivmp/icon.png | Bin 0 -> 2225 bytes backup-website/docs/ivmp/index.php | 66 ++ backup-website/docs/ivmp/metadata.json | 6 + backup-website/docs/jcmp/icon.png | Bin 0 -> 2319 bytes backup-website/docs/jcmp/index.php | 68 ++ backup-website/docs/jcmp/metadata.json | 6 + backup-website/docs/jediknight2/icon.png | Bin 0 -> 2343 bytes backup-website/docs/jediknight2/index.php | 66 ++ backup-website/docs/jediknight2/metadata.json | 6 + backup-website/docs/jediknightja/icon.png | Bin 0 -> 2215 bytes backup-website/docs/jediknightja/index.php | 66 ++ .../docs/jediknightja/metadata.json | 6 + backup-website/docs/killingfloor/icon.jpg | Bin 0 -> 28352 bytes backup-website/docs/killingfloor/index.php | 68 ++ .../docs/killingfloor/metadata.json | 6 + backup-website/docs/killingfloor2/icon.jpg | Bin 0 -> 57305 bytes backup-website/docs/killingfloor2/index.php | 68 ++ .../docs/killingfloor2/metadata.json | 6 + backup-website/docs/left4dead/icon.jpg | Bin 0 -> 57336 bytes backup-website/docs/left4dead/index.php | 68 ++ backup-website/docs/left4dead/metadata.json | 6 + backup-website/docs/left4dead2/icon.jpg | Bin 0 -> 39230 bytes backup-website/docs/left4dead2/index.php | 68 ++ backup-website/docs/left4dead2/metadata.json | 6 + backup-website/docs/lifeisfeudal/icon.png | Bin 0 -> 1854 bytes backup-website/docs/lifeisfeudal/index.php | 68 ++ .../docs/lifeisfeudal/metadata.json | 6 + backup-website/docs/mab_warband/icon.png | Bin 0 -> 2797 bytes backup-website/docs/mab_warband/index.php | 68 ++ backup-website/docs/mab_warband/metadata.json | 6 + backup-website/docs/mafia2online/icon.png | Bin 0 -> 2875 bytes backup-website/docs/mafia2online/index.php | 66 ++ .../docs/mafia2online/metadata.json | 6 + backup-website/docs/minecraft/icon.png | Bin 0 -> 70 bytes backup-website/docs/minecraft/index.php | 634 ++++++++++ backup-website/docs/minecraft/index_old.php | 91 ++ backup-website/docs/minecraft/metadata.json | 6 + backup-website/docs/miscreated/icon.jpg | Bin 0 -> 5570 bytes backup-website/docs/miscreated/index.php | 68 ++ backup-website/docs/miscreated/metadata.json | 6 + backup-website/docs/mohaa/icon.png | Bin 0 -> 3012 bytes backup-website/docs/mohaa/index.php | 66 ++ backup-website/docs/mohaa/metadata.json | 6 + backup-website/docs/mohbr/icon.png | Bin 0 -> 3012 bytes backup-website/docs/mohbr/index.php | 66 ++ backup-website/docs/mohbr/metadata.json | 6 + backup-website/docs/mohsp/icon.png | Bin 0 -> 3012 bytes backup-website/docs/mohsp/index.php | 66 ++ backup-website/docs/mohsp/metadata.json | 6 + backup-website/docs/mohspdemo/icon.png | Bin 0 -> 3012 bytes backup-website/docs/mohspdemo/index.php | 66 ++ backup-website/docs/mohspdemo/metadata.json | 6 + backup-website/docs/mordhau/icon.jpg | Bin 0 -> 51057 bytes backup-website/docs/mordhau/index.php | 68 ++ backup-website/docs/mordhau/metadata.json | 6 + backup-website/docs/multitheftauto/icon.png | Bin 0 -> 2504 bytes backup-website/docs/multitheftauto/index.php | 68 ++ .../docs/multitheftauto/metadata.json | 6 + backup-website/docs/mumble/icon.jpg | Bin 0 -> 47416 bytes backup-website/docs/mumble/index.php | 68 ++ backup-website/docs/mumble/metadata.json | 6 + backup-website/docs/nexuiz/icon.png | Bin 0 -> 2176 bytes backup-website/docs/nexuiz/index.php | 68 ++ backup-website/docs/nexuiz/metadata.json | 6 + backup-website/docs/nmrih_steam/icon.jpg | Bin 0 -> 41993 bytes backup-website/docs/nmrih_steam/index.php | 68 ++ backup-website/docs/nmrih_steam/metadata.json | 6 + backup-website/docs/ns2/icon.png | Bin 0 -> 2413 bytes backup-website/docs/ns2/index.php | 68 ++ backup-website/docs/ns2/metadata.json | 6 + backup-website/docs/nucleardawn/icon.png | Bin 0 -> 2694 bytes backup-website/docs/nucleardawn/index.php | 68 ++ backup-website/docs/nucleardawn/metadata.json | 6 + backup-website/docs/ootow/icon.jpg | Bin 0 -> 43686 bytes backup-website/docs/ootow/index.php | 66 ++ backup-website/docs/ootow/metadata.json | 6 + backup-website/docs/openttd/icon.png | Bin 0 -> 3277 bytes backup-website/docs/openttd/index.php | 68 ++ backup-website/docs/openttd/metadata.json | 6 + backup-website/docs/pixark/icon.png | Bin 0 -> 2233 bytes backup-website/docs/pixark/index.php | 68 ++ backup-website/docs/pixark/metadata.json | 6 + backup-website/docs/pvkii/icon.png | Bin 0 -> 2575 bytes backup-website/docs/pvkii/index.php | 68 ++ backup-website/docs/pvkii/metadata.json | 6 + backup-website/docs/quake3/icon.png | Bin 0 -> 3670 bytes backup-website/docs/quake3/index.php | 68 ++ backup-website/docs/quake3/metadata.json | 6 + backup-website/docs/quake4/icon.png | Bin 0 -> 3559 bytes backup-website/docs/quake4/index.php | 68 ++ backup-website/docs/quake4/metadata.json | 6 + backup-website/docs/redorchestra2/icon.png | Bin 0 -> 3328 bytes backup-website/docs/redorchestra2/index.php | 68 ++ .../docs/redorchestra2/metadata.json | 6 + backup-website/docs/reignofkings/icon.png | Bin 0 -> 3087 bytes backup-website/docs/reignofkings/index.php | 68 ++ .../docs/reignofkings/metadata.json | 6 + backup-website/docs/ricochet/icon.png | Bin 0 -> 2670 bytes backup-website/docs/ricochet/index.php | 68 ++ backup-website/docs/ricochet/metadata.json | 6 + backup-website/docs/risingstorm2/icon.png | Bin 0 -> 3089 bytes backup-website/docs/risingstorm2/index.php | 68 ++ .../docs/risingstorm2/metadata.json | 6 + backup-website/docs/roadkill/icon.png | Bin 0 -> 2519 bytes backup-website/docs/roadkill/index.php | 66 ++ backup-website/docs/roadkill/metadata.json | 6 + backup-website/docs/rorserver/icon.png | Bin 0 -> 2749 bytes backup-website/docs/rorserver/index.php | 66 ++ backup-website/docs/rorserver/metadata.json | 6 + backup-website/docs/rust/icon.png | Bin 0 -> 2242 bytes backup-website/docs/rust/index.php | 455 +++++++ backup-website/docs/rust/index_old.php | 67 ++ backup-website/docs/rust/metadata.json | 6 + backup-website/docs/sanandreasmp/icon.png | Bin 0 -> 3527 bytes backup-website/docs/sanandreasmp/index.php | 68 ++ .../docs/sanandreasmp/metadata.json | 6 + backup-website/docs/serioussamhdfe/icon.png | Bin 0 -> 3518 bytes backup-website/docs/serioussamhdfe/index.php | 66 ++ .../docs/serioussamhdfe/metadata.json | 6 + backup-website/docs/serioussamhdse/icon.png | Bin 0 -> 3518 bytes backup-website/docs/serioussamhdse/index.php | 66 ++ .../docs/serioussamhdse/metadata.json | 6 + backup-website/docs/shoutcast/icon.png | Bin 0 -> 3623 bytes backup-website/docs/shoutcast/index.php | 66 ++ backup-website/docs/shoutcast/metadata.json | 6 + backup-website/docs/shoutcast_bot/icon.png | Bin 0 -> 3623 bytes backup-website/docs/shoutcast_bot/index.php | 66 ++ .../docs/shoutcast_bot/metadata.json | 6 + backup-website/docs/sinusbot/icon.png | Bin 0 -> 3448 bytes backup-website/docs/sinusbot/index.php | 66 ++ backup-website/docs/sinusbot/metadata.json | 6 + backup-website/docs/smashball/icon.png | Bin 0 -> 3182 bytes backup-website/docs/smashball/index.php | 66 ++ backup-website/docs/smashball/metadata.json | 6 + backup-website/docs/smokinguns/icon.png | Bin 0 -> 3526 bytes backup-website/docs/smokinguns/index.php | 68 ++ backup-website/docs/smokinguns/metadata.json | 6 + backup-website/docs/sms/icon.png | Bin 0 -> 3303 bytes backup-website/docs/sms/index.php | 66 ++ backup-website/docs/sms/metadata.json | 6 + backup-website/docs/sniperelitev2/icon.png | Bin 0 -> 3524 bytes backup-website/docs/sniperelitev2/index.php | 66 ++ .../docs/sniperelitev2/metadata.json | 6 + backup-website/docs/soldatserver/icon.png | Bin 0 -> 3064 bytes backup-website/docs/soldatserver/index.php | 66 ++ .../docs/soldatserver/metadata.json | 6 + backup-website/docs/space_engineers/icon.jpg | Bin 0 -> 142929 bytes backup-website/docs/space_engineers/index.php | 68 ++ .../docs/space_engineers/metadata.json | 6 + backup-website/docs/spigotmc/icon.png | Bin 0 -> 3540 bytes backup-website/docs/spigotmc/index.php | 68 ++ backup-website/docs/spigotmc/metadata.json | 6 + backup-website/docs/spunkybot/icon.jpg | Bin 0 -> 21286 bytes backup-website/docs/spunkybot/index.php | 66 ++ backup-website/docs/spunkybot/metadata.json | 6 + backup-website/docs/squad/icon.jpg | Bin 0 -> 60703 bytes backup-website/docs/squad/index.php | 68 ++ backup-website/docs/squad/metadata.json | 6 + backup-website/docs/starbound/icon.jpg | Bin 0 -> 25697 bytes backup-website/docs/starbound/index.php | 68 ++ backup-website/docs/starbound/metadata.json | 6 + backup-website/docs/stationeers/icon.jpg | Bin 0 -> 44708 bytes backup-website/docs/stationeers/index.php | 68 ++ backup-website/docs/stationeers/metadata.json | 6 + backup-website/docs/synergy/icon.png | Bin 0 -> 3268 bytes backup-website/docs/synergy/index.php | 68 ++ backup-website/docs/synergy/metadata.json | 6 + backup-website/docs/teamspeak2/icon.png | Bin 0 -> 2145 bytes backup-website/docs/teamspeak2/index.php | 68 ++ backup-website/docs/teamspeak2/metadata.json | 6 + backup-website/docs/teamspeak3/icon.png | Bin 0 -> 2178 bytes backup-website/docs/teamspeak3/index.php | 68 ++ backup-website/docs/teamspeak3/metadata.json | 6 + backup-website/docs/terraria/icon.jpg | Bin 0 -> 62177 bytes backup-website/docs/terraria/index.php | 360 ++++++ backup-website/docs/terraria/metadata.json | 6 + backup-website/docs/tf2/icon.jpg | Bin 0 -> 55689 bytes backup-website/docs/tf2/index.php | 156 +++ backup-website/docs/tf2/index_old.php | 68 ++ backup-website/docs/tf2/metadata.json | 6 + backup-website/docs/tfc/icon.png | Bin 0 -> 1985 bytes backup-website/docs/tfc/index.php | 66 ++ backup-website/docs/tfc/metadata.json | 6 + backup-website/docs/theforest/icon.png | Bin 0 -> 1752 bytes backup-website/docs/theforest/index.php | 68 ++ backup-website/docs/theforest/metadata.json | 6 + .../docs/trackmanianations/icon.png | Bin 0 -> 1883 bytes .../docs/trackmanianations/index.php | 66 ++ .../docs/trackmanianations/metadata.json | 6 + backup-website/docs/trackmanianf/icon.png | Bin 0 -> 1883 bytes backup-website/docs/trackmanianf/index.php | 66 ++ .../docs/trackmanianf/metadata.json | 6 + backup-website/docs/unturned/icon.jpg | Bin 0 -> 2087 bytes backup-website/docs/unturned/index.php | 68 ++ backup-website/docs/unturned/metadata.json | 6 + backup-website/docs/urt/icon.jpg | Bin 0 -> 26474 bytes backup-website/docs/urt/index.php | 68 ++ backup-website/docs/urt/metadata.json | 6 + backup-website/docs/ut2004/icon.png | Bin 0 -> 2437 bytes backup-website/docs/ut2004/index.php | 68 ++ backup-website/docs/ut2004/metadata.json | 6 + backup-website/docs/ut3/icon.png | Bin 0 -> 2437 bytes backup-website/docs/ut3/index.php | 68 ++ backup-website/docs/ut3/metadata.json | 6 + backup-website/docs/ut99/icon.png | Bin 0 -> 2437 bytes backup-website/docs/ut99/index.php | 68 ++ backup-website/docs/ut99/metadata.json | 6 + backup-website/docs/valheim/icon.jpg | Bin 0 -> 50327 bytes backup-website/docs/valheim/index.php | 326 +++++ backup-website/docs/valheim/metadata.json | 6 + backup-website/docs/vbox/icon.png | Bin 0 -> 3061 bytes backup-website/docs/vbox/index.php | 66 ++ backup-website/docs/vbox/metadata.json | 6 + backup-website/docs/ventrilo/icon.png | Bin 0 -> 2781 bytes backup-website/docs/ventrilo/index.php | 68 ++ backup-website/docs/ventrilo/metadata.json | 6 + backup-website/docs/vicecitymp/icon.png | Bin 0 -> 3295 bytes backup-website/docs/vicecitymp/index.php | 66 ++ backup-website/docs/vicecitymp/metadata.json | 6 + backup-website/docs/warsow/icon.png | Bin 0 -> 3332 bytes backup-website/docs/warsow/index.php | 68 ++ backup-website/docs/warsow/metadata.json | 6 + backup-website/docs/wolfrtcw_1-4/icon.png | Bin 0 -> 3474 bytes backup-website/docs/wolfrtcw_1-4/index.php | 66 ++ .../docs/wolfrtcw_1-4/metadata.json | 6 + backup-website/docs/wreckfest/icon.png | Bin 0 -> 3425 bytes backup-website/docs/wreckfest/index.php | 68 ++ backup-website/docs/wreckfest/metadata.json | 6 + backup-website/docs/wurmu/icon.jpg | Bin 0 -> 47158 bytes backup-website/docs/wurmu/index.php | 68 ++ backup-website/docs/wurmu/metadata.json | 6 + backup-website/docs/xonotic/icon.png | Bin 0 -> 3129 bytes backup-website/docs/xonotic/index.php | 68 ++ backup-website/docs/xonotic/metadata.json | 6 + backup-website/docs/zps/icon.png | Bin 0 -> 2845 bytes backup-website/docs/zps/index.php | 68 ++ backup-website/docs/zps/metadata.json | 6 + backup-website/error_log | 155 +++ backup-website/fix_invoices_table_columns.sql | 205 ++++ backup-website/forgot_password.php | 293 +++++ backup-website/images/banner.png | Bin 0 -> 284540 bytes backup-website/images/bf3_the_russian.jpg | Bin 0 -> 159892 bytes backup-website/images/dark.jpg | Bin 0 -> 659147 bytes backup-website/images/featured/7dtd.jpg | Bin 0 -> 40986 bytes backup-website/images/featured/arkse.jpg | Bin 0 -> 133659 bytes .../featured/arma2_operation_arrowhead.jpg | Bin 0 -> 52834 bytes backup-website/images/featured/arma_3.jpg | Bin 0 -> 33192 bytes backup-website/images/featured/cs_go.jpg | Bin 0 -> 23981 bytes backup-website/images/featured/day_z.jpg | Bin 0 -> 28105 bytes .../images/featured/dayz_epochmod.jpg | Bin 0 -> 6556 bytes backup-website/images/featured/dayz_mod.jpg | Bin 0 -> 37224 bytes backup-website/images/featured/eurotruck2.jpg | Bin 0 -> 41153 bytes .../images/featured/fistful_of_frags.jpg | Bin 0 -> 52615 bytes backup-website/images/featured/insurgency.jpg | Bin 0 -> 34600 bytes .../images/featured/insurgency_sandstorm.jpg | Bin 0 -> 39090 bytes backup-website/images/featured/minecraft.jpg | Bin 0 -> 53010 bytes backup-website/images/games/7dtd.jpg | Bin 0 -> 40986 bytes backup-website/images/games/arkse.jpg | Bin 0 -> 133659 bytes backup-website/images/games/arma2.jpg | Bin 0 -> 40955 bytes .../games/arma2_operation_arrowhead.jpg | Bin 0 -> 52834 bytes backup-website/images/games/arma_3.jpg | Bin 0 -> 33192 bytes backup-website/images/games/asseto.jpg | Bin 0 -> 50562 bytes backup-website/images/games/avorion.jpg | Bin 0 -> 32342 bytes backup-website/images/games/brainbread_2.jpg | Bin 0 -> 175402 bytes backup-website/images/games/chivalry.jpg | Bin 0 -> 115345 bytes backup-website/images/games/citadel.jpg | Bin 0 -> 59357 bytes .../images/games/colonysurvival.jpg | Bin 0 -> 47610 bytes backup-website/images/games/conanexiles.jpg | Bin 0 -> 37168 bytes backup-website/images/games/cs_go.jpg | Bin 0 -> 23981 bytes backup-website/images/games/cstrike.jpg | Bin 0 -> 28138 bytes backup-website/images/games/cstrikesource.jpg | Bin 0 -> 18125 bytes .../images/games/day_of_defeat_source.jpg | Bin 0 -> 25387 bytes backup-website/images/games/day_z.jpg | Bin 0 -> 28105 bytes backup-website/images/games/dayz_epochmod.jpg | Bin 0 -> 6556 bytes backup-website/images/games/dayz_mod.jpg | Bin 0 -> 37224 bytes .../images/games/deathmatch_classic.jpg | Bin 0 -> 32228 bytes backup-website/images/games/dst.jpg | Bin 0 -> 56997 bytes backup-website/images/games/eco.jpg | Bin 0 -> 44396 bytes backup-website/images/games/eurotruck2.jpg | Bin 0 -> 41153 bytes .../images/games/fistful_of_frags.jpg | Bin 0 -> 52615 bytes backup-website/images/games/garrys_mod.jpg | Bin 0 -> 20463 bytes .../images/games/half-life2_deathmatch.jpg | Bin 0 -> 25477 bytes backup-website/images/games/harsh.jpg | Bin 0 -> 39125 bytes backup-website/images/games/hurt_world.jpg | Bin 0 -> 35501 bytes backup-website/images/games/insurgency.jpg | Bin 0 -> 34600 bytes .../images/games/insurgency_sandstorm.jpg | Bin 0 -> 39090 bytes backup-website/images/games/killing_floor.jpg | Bin 0 -> 28352 bytes .../images/games/killing_floor_2.jpg | Bin 0 -> 57305 bytes backup-website/images/games/left_4_dead.jpg | Bin 0 -> 57336 bytes backup-website/images/games/left_4_dead_2.jpg | Bin 0 -> 39230 bytes backup-website/images/games/minecraft.jpg | Bin 0 -> 53010 bytes .../images/games/miscreated_server.jpg | Bin 0 -> 35617 bytes backup-website/images/games/mordhau.jpg | Bin 0 -> 51057 bytes .../images/games/nomoreroominhell.jpg | Bin 0 -> 41993 bytes backup-website/images/games/ootow.jpg | Bin 0 -> 43686 bytes backup-website/images/games/rust_header.jpg | Bin 0 -> 15212 bytes backup-website/images/games/scp.jpg | Bin 0 -> 29895 bytes backup-website/images/games/squad.jpg | Bin 0 -> 60703 bytes backup-website/images/games/starbound.jpg | Bin 0 -> 25697 bytes backup-website/images/games/stationeers.jpg | Bin 0 -> 44708 bytes .../images/games/team_fortress_2.jpg | Bin 0 -> 55689 bytes backup-website/images/games/terraria.jpg | Bin 0 -> 62177 bytes backup-website/images/games/urt.jpg | Bin 0 -> 26474 bytes backup-website/images/games/valheim.jpg | Bin 0 -> 50327 bytes backup-website/images/games/wurmu.jpg | Bin 0 -> 47158 bytes backup-website/images/logo-sm.png | Bin 0 -> 20171 bytes backup-website/images/logo.jpg | Bin 0 -> 54815 bytes backup-website/images/logo.png | Bin 0 -> 302940 bytes backup-website/includes/README.md | 28 + backup-website/includes/admin_auth.php | 68 ++ backup-website/includes/cart_helper.php | 22 + backup-website/includes/config.inc.php | 32 + backup-website/includes/config.inc.php.orig | 32 + backup-website/includes/footer.php | 21 + backup-website/includes/log.php | 33 + backup-website/includes/login_required.php | 11 + backup-website/includes/menu.php | 124 ++ backup-website/includes/payment_processor.php | 228 ++++ backup-website/includes/top.php | 6 + backup-website/index.php | 97 ++ backup-website/invoices.php | 66 ++ backup-website/logfile.txt | 15 + backup-website/login.php | 312 +++++ backup-website/logout.php | 32 + backup-website/logs/payment_capture.log | 75 ++ backup-website/migration_to_invoices.sql | 176 +++ backup-website/module.php | 120 ++ backup-website/my_account.php | 394 ++++++ backup-website/my_servers.php | 151 +++ backup-website/order.php | 322 +++++ backup-website/payment_cancel.php | 51 + backup-website/payment_success.php | 226 ++++ backup-website/privacy.php | 49 + backup-website/register.php | 72 ++ backup-website/renew_server.php | 279 +++++ backup-website/reset_password.php | 303 +++++ backup-website/return.php | 114 ++ backup-website/server_status.php | 173 +++ backup-website/serverlist.php | 138 +++ backup-website/test_db_connection.php | 157 +++ backup-website/timestamp.txt | 1 + backup-website/tools/check_db_user.php | 30 + .../tools/check_invoices_redirect.php | 16 + .../tools/check_logout_redirect.php | 21 + .../tools/debug_invoices_redirect.php | 40 + backup-website/tools/simulate_webhook.php | 39 + backup-website/tos.php | 57 + backup-website/webhook.php | 163 +++ backup-website/well-known.zip | Bin 0 -> 6979639 bytes docs/modules/website.md | 24 +- docs/modules/website_billing_rebuild.md | 218 ++++ 680 files changed, 33650 insertions(+), 43 deletions(-) create mode 100644 Panel/modules/website/admin.php create mode 100644 Panel/modules/website/api/capture_order.php create mode 100644 Panel/modules/website/api/create_order.php create mode 100644 Panel/modules/website/checkout.php create mode 100644 Panel/modules/website/forgot_password.php create mode 100644 Panel/modules/website/includes/billing.php create mode 100644 Panel/modules/website/invoices.php create mode 100644 Panel/modules/website/my_servers.php create mode 100644 Panel/modules/website/orders.php create mode 100644 Panel/modules/website/pages/checkout.php create mode 100644 Panel/modules/website/pages/forgot_password.php create mode 100644 Panel/modules/website/pages/invoices.php create mode 100644 Panel/modules/website/pages/message.php create mode 100644 Panel/modules/website/pages/my_servers.php create mode 100644 Panel/modules/website/pages/orders.php create mode 100644 Panel/modules/website/pages/register.php create mode 100644 Panel/modules/website/pages/reset_password.php create mode 100644 Panel/modules/website/pages/staff.php create mode 100644 Panel/modules/website/pages/staff_coupons.php create mode 100644 Panel/modules/website/pages/staff_invoices.php create mode 100644 Panel/modules/website/pages/staff_locations.php create mode 100644 Panel/modules/website/pages/staff_migrations.php create mode 100644 Panel/modules/website/pages/staff_orders.php create mode 100644 Panel/modules/website/pages/staff_payments.php create mode 100644 Panel/modules/website/pages/staff_paypal.php create mode 100644 Panel/modules/website/pages/staff_provisioning.php create mode 100644 Panel/modules/website/pages/staff_services.php create mode 100644 Panel/modules/website/pages/staff_settings.php create mode 100644 Panel/modules/website/payment_cancel.php create mode 100644 Panel/modules/website/payment_success.php create mode 100644 Panel/modules/website/register.php create mode 100644 Panel/modules/website/reset_password.php create mode 100644 Panel/modules/website/staff.php create mode 100644 Panel/modules/website/staff_coupons.php create mode 100644 Panel/modules/website/staff_invoices.php create mode 100644 Panel/modules/website/staff_locations.php create mode 100644 Panel/modules/website/staff_migrations.php create mode 100644 Panel/modules/website/staff_orders.php create mode 100644 Panel/modules/website/staff_payments.php create mode 100644 Panel/modules/website/staff_paypal.php create mode 100644 Panel/modules/website/staff_provisioning.php create mode 100644 Panel/modules/website/staff_services.php create mode 100644 Panel/modules/website/staff_settings.php create mode 100644 Panel/modules/website/webhook.php create mode 100644 backup-website/.htaccess create mode 100644 backup-website/BILLING_FIX_SUMMARY.md create mode 100644 backup-website/COLUMN_RENAME_SUMMARY.md create mode 100644 backup-website/COUPON_SYSTEM.md create mode 100644 backup-website/FIXES_APPLIED.md create mode 100644 backup-website/INVOICE_FIRST_FLOW.md create mode 100644 backup-website/INVOICE_SYSTEM.md create mode 100644 backup-website/LOGGING_CHANGES_SUMMARY.md create mode 100644 backup-website/MIGRATION_SUMMARY.md create mode 100644 backup-website/PAYMENT_IMPLEMENTATION_SUMMARY.md create mode 100644 backup-website/PAYPAL_DEBUGGING_GUIDE.md create mode 100644 backup-website/QUICK_DEBUG_REFERENCE.md create mode 100644 backup-website/README_COUPON_UPDATE.md create mode 100644 backup-website/RECENT_FIXES_SUMMARY.md create mode 100644 backup-website/STATUS_REPORT.md create mode 100644 backup-website/TESTING_CHECKLIST.md create mode 100644 backup-website/_archived/CONFIGURATION.md create mode 100644 backup-website/_archived/FEATURES.md create mode 100644 backup-website/_archived/IMPLEMENTATION_SUMMARY.md create mode 100644 backup-website/_archived/README_LOGIN.md create mode 100644 backup-website/_archived/VISUAL_GUIDE.md create mode 100644 backup-website/_archived/removed-20251023-142000/ARCHIVE_README.txt create mode 100644 backup-website/_archived/removed-20251023-142000/MOVED_DOCS.md create mode 100644 backup-website/_archived/removed-20251023-202500/MOVED_FILES.json create mode 100644 backup-website/_archived/removed-20251023-202500/ai.php create mode 100644 backup-website/_archived/removed-20251023-202500/data/FREE-548-1761171178.json create mode 100644 backup-website/_archived/removed-20251023-202500/data/FREE-549-1761246925.json create mode 100644 backup-website/_archived/removed-20251023-202500/data/INV-20250825-170438-e37518.json create mode 100644 backup-website/_archived/removed-20251023-202500/data/INV-20250825-174311-0a7993.json create mode 100644 backup-website/_archived/removed-20251023-202500/data/NO-INVOICE.json create mode 100644 backup-website/_archived/removed-20251023-202500/data/SIMULATED-WEBHOOK-20251022-101500.json create mode 100644 backup-website/add_paypal_data_column.sql create mode 100644 backup-website/add_service_id_column.sql create mode 100644 backup-website/add_to_cart.php create mode 100644 backup-website/admin.php create mode 100644 backup-website/admin_config.php create mode 100644 backup-website/admin_coupons.php create mode 100644 backup-website/admin_invoices.php create mode 100644 backup-website/admin_payments.php create mode 100644 backup-website/adminserverlist.php create mode 100644 backup-website/ai.php create mode 100644 backup-website/api/capture_order.php create mode 100644 backup-website/api/create_order.php create mode 100644 backup-website/api/error_log create mode 100644 backup-website/api/log_error.php create mode 100644 backup-website/bootstrap.php create mode 100644 backup-website/cart.php create mode 100644 backup-website/check_table.php create mode 100644 backup-website/cleanupDB.sh create mode 100644 backup-website/create_coupons_table.sql create mode 100644 backup-website/create_invoices_table.sql create mode 100644 backup-website/create_servers.php create mode 100644 backup-website/cron-shop.php create mode 100644 backup-website/css/header.css create mode 100644 backup-website/data/debug_cart.log create mode 100644 backup-website/diag_remote.php create mode 100644 backup-website/docs.php create mode 100644 backup-website/docs/7daystodie/icon.jpg create mode 100644 backup-website/docs/7daystodie/index.php create mode 100644 backup-website/docs/7daystodie/metadata.json create mode 100644 backup-website/docs/DOCUMENTATION_ENHANCEMENT_SUMMARY.md create mode 100644 backup-website/docs/DOCUMENTATION_EXPANSION_PLAN.md create mode 100644 backup-website/docs/Game Server Hosting Reference (Multiplayer PC Games).pdf create mode 100644 backup-website/docs/README.md create mode 100644 backup-website/docs/aliensvspredator/icon.png create mode 100644 backup-website/docs/aliensvspredator/index.php create mode 100644 backup-website/docs/aliensvspredator/metadata.json create mode 100644 backup-website/docs/aoc/icon.png create mode 100644 backup-website/docs/aoc/index.php create mode 100644 backup-website/docs/aoc/metadata.json create mode 100644 backup-website/docs/arkse/icon.jpg create mode 100644 backup-website/docs/arkse/index.php create mode 100644 backup-website/docs/arkse/metadata.json create mode 100644 backup-website/docs/arma-reforger/icon.png create mode 100644 backup-website/docs/arma-reforger/index.php create mode 100644 backup-website/docs/arma-reforger/metadata.json create mode 100644 backup-website/docs/arma2co/icon.png create mode 100644 backup-website/docs/arma2co/index.php create mode 100644 backup-website/docs/arma2co/metadata.json create mode 100644 backup-website/docs/arma2oa/icon.jpg create mode 100644 backup-website/docs/arma2oa/index.php create mode 100644 backup-website/docs/arma2oa/metadata.json create mode 100644 backup-website/docs/arma3/icon.jpg create mode 100644 backup-website/docs/arma3/index.php create mode 100644 backup-website/docs/arma3/metadata.json create mode 100644 backup-website/docs/assettocorsa/icon.png create mode 100644 backup-website/docs/assettocorsa/index.php create mode 100644 backup-website/docs/assettocorsa/metadata.json create mode 100644 backup-website/docs/atlas/icon.png create mode 100644 backup-website/docs/atlas/index.php create mode 100644 backup-website/docs/atlas/metadata.json create mode 100644 backup-website/docs/avorion/icon.jpg create mode 100644 backup-website/docs/avorion/index.php create mode 100644 backup-website/docs/avorion/metadata.json create mode 100644 backup-website/docs/bec/icon.jpg create mode 100644 backup-website/docs/bec/index.php create mode 100644 backup-website/docs/bec/metadata.json create mode 100644 backup-website/docs/bf2/icon.png create mode 100644 backup-website/docs/bf2/index.php create mode 100644 backup-website/docs/bf2/metadata.json create mode 100644 backup-website/docs/bfbc2/icon.png create mode 100644 backup-website/docs/bfbc2/index.php create mode 100644 backup-website/docs/bfbc2/metadata.json create mode 100644 backup-website/docs/bigbrotherbot/icon.png create mode 100644 backup-website/docs/bigbrotherbot/index.php create mode 100644 backup-website/docs/bigbrotherbot/metadata.json create mode 100644 backup-website/docs/bloodfrontier/icon.png create mode 100644 backup-website/docs/bloodfrontier/index.php create mode 100644 backup-website/docs/bloodfrontier/metadata.json create mode 100644 backup-website/docs/brainbread2/icon.jpg create mode 100644 backup-website/docs/brainbread2/index.php create mode 100644 backup-website/docs/brainbread2/metadata.json create mode 100644 backup-website/docs/callofduty/icon.png create mode 100644 backup-website/docs/callofduty/index.php create mode 100644 backup-website/docs/callofduty/metadata.json create mode 100644 backup-website/docs/callofduty2/icon.png create mode 100644 backup-website/docs/callofduty2/index.php create mode 100644 backup-website/docs/callofduty2/metadata.json create mode 100644 backup-website/docs/callofduty4mw/icon.png create mode 100644 backup-website/docs/callofduty4mw/index.php create mode 100644 backup-website/docs/callofduty4mw/metadata.json create mode 100644 backup-website/docs/callofdutymw2/icon.png create mode 100644 backup-website/docs/callofdutymw2/index.php create mode 100644 backup-website/docs/callofdutymw2/metadata.json create mode 100644 backup-website/docs/callofdutymw3/icon.png create mode 100644 backup-website/docs/callofdutymw3/index.php create mode 100644 backup-website/docs/callofdutymw3/metadata.json create mode 100644 backup-website/docs/callofdutyuo/icon.png create mode 100644 backup-website/docs/callofdutyuo/index.php create mode 100644 backup-website/docs/callofdutyuo/metadata.json create mode 100644 backup-website/docs/callofdutywaw/icon.png create mode 100644 backup-website/docs/callofdutywaw/index.php create mode 100644 backup-website/docs/callofdutywaw/metadata.json create mode 100644 backup-website/docs/citadelfwf/icon.png create mode 100644 backup-website/docs/citadelfwf/index.php create mode 100644 backup-website/docs/citadelfwf/metadata.json create mode 100644 backup-website/docs/cod_blackops/icon.png create mode 100644 backup-website/docs/cod_blackops/index.php create mode 100644 backup-website/docs/cod_blackops/metadata.json create mode 100644 backup-website/docs/colonysurvival/icon.jpg create mode 100644 backup-website/docs/colonysurvival/index.php create mode 100644 backup-website/docs/colonysurvival/metadata.json create mode 100644 backup-website/docs/common-issues/icon.png create mode 100644 backup-website/docs/common-issues/index.php create mode 100644 backup-website/docs/common-issues/metadata.json create mode 100644 backup-website/docs/conanexiles/icon.jpg create mode 100644 backup-website/docs/conanexiles/index.php create mode 100644 backup-website/docs/conanexiles/metadata.json create mode 100644 backup-website/docs/cs2d/icon.png create mode 100644 backup-website/docs/cs2d/index.php create mode 100644 backup-website/docs/cs2d/metadata.json create mode 100644 backup-website/docs/csgo/icon.png create mode 100644 backup-website/docs/csgo/index.php create mode 100644 backup-website/docs/csgo/index_old.php create mode 100644 backup-website/docs/csgo/metadata.json create mode 100644 backup-website/docs/cspromod/icon.png create mode 100644 backup-website/docs/cspromod/index.php create mode 100644 backup-website/docs/cspromod/metadata.json create mode 100644 backup-website/docs/css/icon.jpg create mode 100644 backup-website/docs/css/index.php create mode 100644 backup-website/docs/css/metadata.json create mode 100644 backup-website/docs/cstrike/icon.jpg create mode 100644 backup-website/docs/cstrike/index.php create mode 100644 backup-website/docs/cstrike/metadata.json create mode 100644 backup-website/docs/czero/icon.png create mode 100644 backup-website/docs/czero/index.php create mode 100644 backup-website/docs/czero/metadata.json create mode 100644 backup-website/docs/dayz/icon.png create mode 100644 backup-website/docs/dayz/index.php create mode 100644 backup-website/docs/dayz/metadata.json create mode 100644 backup-website/docs/dayzmod/icon.jpg create mode 100644 backup-website/docs/dayzmod/index.php create mode 100644 backup-website/docs/dayzmod/metadata.json create mode 100644 backup-website/docs/dmc/icon.jpg create mode 100644 backup-website/docs/dmc/index.php create mode 100644 backup-website/docs/dmc/metadata.json create mode 100644 backup-website/docs/dod/icon.png create mode 100644 backup-website/docs/dod/index.php create mode 100644 backup-website/docs/dod/metadata.json create mode 100644 backup-website/docs/dods/icon.jpg create mode 100644 backup-website/docs/dods/index.php create mode 100644 backup-website/docs/dods/metadata.json create mode 100644 backup-website/docs/doi/icon.jpg create mode 100644 backup-website/docs/doi/index.php create mode 100644 backup-website/docs/doi/metadata.json create mode 100644 backup-website/docs/dontstarvetogether/icon.png create mode 100644 backup-website/docs/dontstarvetogether/index.php create mode 100644 backup-website/docs/dontstarvetogether/metadata.json create mode 100644 backup-website/docs/dystopia/icon.png create mode 100644 backup-website/docs/dystopia/index.php create mode 100644 backup-website/docs/dystopia/metadata.json create mode 100644 backup-website/docs/eco/icon.jpg create mode 100644 backup-website/docs/eco/index.php create mode 100644 backup-website/docs/eco/metadata.json create mode 100644 backup-website/docs/empyriongs/icon.png create mode 100644 backup-website/docs/empyriongs/index.php create mode 100644 backup-website/docs/empyriongs/metadata.json create mode 100644 backup-website/docs/enemyterritory/icon.png create mode 100644 backup-website/docs/enemyterritory/index.php create mode 100644 backup-website/docs/enemyterritory/metadata.json create mode 100644 backup-website/docs/epochmod/icon.png create mode 100644 backup-website/docs/epochmod/index.php create mode 100644 backup-website/docs/epochmod/metadata.json create mode 100644 backup-website/docs/esmod/icon.png create mode 100644 backup-website/docs/esmod/index.php create mode 100644 backup-website/docs/esmod/metadata.json create mode 100644 backup-website/docs/ets2/icon.png create mode 100644 backup-website/docs/ets2/index.php create mode 100644 backup-website/docs/ets2/metadata.json create mode 100644 backup-website/docs/factorio/icon.jpg create mode 100644 backup-website/docs/factorio/index.php create mode 100644 backup-website/docs/factorio/metadata.json create mode 100644 backup-website/docs/feedthebeast/icon.png create mode 100644 backup-website/docs/feedthebeast/index.php create mode 100644 backup-website/docs/feedthebeast/metadata.json create mode 100644 backup-website/docs/fgms/icon.png create mode 100644 backup-website/docs/fgms/index.php create mode 100644 backup-website/docs/fgms/metadata.json create mode 100644 backup-website/docs/fivem/icon.png create mode 100644 backup-website/docs/fivem/index.php create mode 100644 backup-website/docs/fivem/metadata.json create mode 100644 backup-website/docs/fof/icon.jpg create mode 100644 backup-website/docs/fof/index.php create mode 100644 backup-website/docs/fof/metadata.json create mode 100644 backup-website/docs/freecol/icon.png create mode 100644 backup-website/docs/freecol/index.php create mode 100644 backup-website/docs/freecol/metadata.json create mode 100644 backup-website/docs/gameserver_catalog_all_sources.yaml create mode 100644 backup-website/docs/gameserver_catalog_lgsm_full.yaml create mode 100644 backup-website/docs/gameserver_knowledgepack_v2.yaml create mode 100644 backup-website/docs/garrysmod/icon.jpg create mode 100644 backup-website/docs/garrysmod/index.php create mode 100644 backup-website/docs/garrysmod/metadata.json create mode 100644 backup-website/docs/gearbox/icon.png create mode 100644 backup-website/docs/gearbox/index.php create mode 100644 backup-website/docs/gearbox/metadata.json create mode 100644 backup-website/docs/getting-started/icon.png create mode 100644 backup-website/docs/getting-started/index.php create mode 100644 backup-website/docs/getting-started/metadata.json create mode 100644 backup-website/docs/halo_ce/icon.png create mode 100644 backup-website/docs/halo_ce/index.php create mode 100644 backup-website/docs/halo_ce/metadata.json create mode 100644 backup-website/docs/harsh/icon.jpg create mode 100644 backup-website/docs/harsh/index.php create mode 100644 backup-website/docs/harsh/metadata.json create mode 100644 backup-website/docs/hidden_source/icon.png create mode 100644 backup-website/docs/hidden_source/index.php create mode 100644 backup-website/docs/hidden_source/metadata.json create mode 100644 backup-website/docs/hl2d/icon.png create mode 100644 backup-website/docs/hl2d/index.php create mode 100644 backup-website/docs/hl2d/metadata.json create mode 100644 backup-website/docs/hldm/icon.png create mode 100644 backup-website/docs/hldm/index.php create mode 100644 backup-website/docs/hldm/metadata.json create mode 100644 backup-website/docs/hltv/icon.png create mode 100644 backup-website/docs/hltv/index.php create mode 100644 backup-website/docs/hltv/metadata.json create mode 100644 backup-website/docs/homefront/icon.png create mode 100644 backup-website/docs/homefront/index.php create mode 100644 backup-website/docs/homefront/metadata.json create mode 100644 backup-website/docs/hurtworld/icon.jpg create mode 100644 backup-website/docs/hurtworld/index.php create mode 100644 backup-website/docs/hurtworld/metadata.json create mode 100644 backup-website/docs/il2/icon.png create mode 100644 backup-website/docs/il2/index.php create mode 100644 backup-website/docs/il2/metadata.json create mode 100644 backup-website/docs/ins/icon.jpg create mode 100644 backup-website/docs/ins/index.php create mode 100644 backup-website/docs/ins/metadata.json create mode 100644 backup-website/docs/insurgencymic/icon.png create mode 100644 backup-website/docs/insurgencymic/index.php create mode 100644 backup-website/docs/insurgencymic/metadata.json create mode 100644 backup-website/docs/insurgencysandstorm/icon.png create mode 100644 backup-website/docs/insurgencysandstorm/index.php create mode 100644 backup-website/docs/insurgencysandstorm/metadata.json create mode 100644 backup-website/docs/ivmp/icon.png create mode 100644 backup-website/docs/ivmp/index.php create mode 100644 backup-website/docs/ivmp/metadata.json create mode 100644 backup-website/docs/jcmp/icon.png create mode 100644 backup-website/docs/jcmp/index.php create mode 100644 backup-website/docs/jcmp/metadata.json create mode 100644 backup-website/docs/jediknight2/icon.png create mode 100644 backup-website/docs/jediknight2/index.php create mode 100644 backup-website/docs/jediknight2/metadata.json create mode 100644 backup-website/docs/jediknightja/icon.png create mode 100644 backup-website/docs/jediknightja/index.php create mode 100644 backup-website/docs/jediknightja/metadata.json create mode 100644 backup-website/docs/killingfloor/icon.jpg create mode 100644 backup-website/docs/killingfloor/index.php create mode 100644 backup-website/docs/killingfloor/metadata.json create mode 100644 backup-website/docs/killingfloor2/icon.jpg create mode 100644 backup-website/docs/killingfloor2/index.php create mode 100644 backup-website/docs/killingfloor2/metadata.json create mode 100644 backup-website/docs/left4dead/icon.jpg create mode 100644 backup-website/docs/left4dead/index.php create mode 100644 backup-website/docs/left4dead/metadata.json create mode 100644 backup-website/docs/left4dead2/icon.jpg create mode 100644 backup-website/docs/left4dead2/index.php create mode 100644 backup-website/docs/left4dead2/metadata.json create mode 100644 backup-website/docs/lifeisfeudal/icon.png create mode 100644 backup-website/docs/lifeisfeudal/index.php create mode 100644 backup-website/docs/lifeisfeudal/metadata.json create mode 100644 backup-website/docs/mab_warband/icon.png create mode 100644 backup-website/docs/mab_warband/index.php create mode 100644 backup-website/docs/mab_warband/metadata.json create mode 100644 backup-website/docs/mafia2online/icon.png create mode 100644 backup-website/docs/mafia2online/index.php create mode 100644 backup-website/docs/mafia2online/metadata.json create mode 100644 backup-website/docs/minecraft/icon.png create mode 100644 backup-website/docs/minecraft/index.php create mode 100644 backup-website/docs/minecraft/index_old.php create mode 100644 backup-website/docs/minecraft/metadata.json create mode 100644 backup-website/docs/miscreated/icon.jpg create mode 100644 backup-website/docs/miscreated/index.php create mode 100644 backup-website/docs/miscreated/metadata.json create mode 100644 backup-website/docs/mohaa/icon.png create mode 100644 backup-website/docs/mohaa/index.php create mode 100644 backup-website/docs/mohaa/metadata.json create mode 100644 backup-website/docs/mohbr/icon.png create mode 100644 backup-website/docs/mohbr/index.php create mode 100644 backup-website/docs/mohbr/metadata.json create mode 100644 backup-website/docs/mohsp/icon.png create mode 100644 backup-website/docs/mohsp/index.php create mode 100644 backup-website/docs/mohsp/metadata.json create mode 100644 backup-website/docs/mohspdemo/icon.png create mode 100644 backup-website/docs/mohspdemo/index.php create mode 100644 backup-website/docs/mohspdemo/metadata.json create mode 100644 backup-website/docs/mordhau/icon.jpg create mode 100644 backup-website/docs/mordhau/index.php create mode 100644 backup-website/docs/mordhau/metadata.json create mode 100644 backup-website/docs/multitheftauto/icon.png create mode 100644 backup-website/docs/multitheftauto/index.php create mode 100644 backup-website/docs/multitheftauto/metadata.json create mode 100644 backup-website/docs/mumble/icon.jpg create mode 100644 backup-website/docs/mumble/index.php create mode 100644 backup-website/docs/mumble/metadata.json create mode 100644 backup-website/docs/nexuiz/icon.png create mode 100644 backup-website/docs/nexuiz/index.php create mode 100644 backup-website/docs/nexuiz/metadata.json create mode 100644 backup-website/docs/nmrih_steam/icon.jpg create mode 100644 backup-website/docs/nmrih_steam/index.php create mode 100644 backup-website/docs/nmrih_steam/metadata.json create mode 100644 backup-website/docs/ns2/icon.png create mode 100644 backup-website/docs/ns2/index.php create mode 100644 backup-website/docs/ns2/metadata.json create mode 100644 backup-website/docs/nucleardawn/icon.png create mode 100644 backup-website/docs/nucleardawn/index.php create mode 100644 backup-website/docs/nucleardawn/metadata.json create mode 100644 backup-website/docs/ootow/icon.jpg create mode 100644 backup-website/docs/ootow/index.php create mode 100644 backup-website/docs/ootow/metadata.json create mode 100644 backup-website/docs/openttd/icon.png create mode 100644 backup-website/docs/openttd/index.php create mode 100644 backup-website/docs/openttd/metadata.json create mode 100644 backup-website/docs/pixark/icon.png create mode 100644 backup-website/docs/pixark/index.php create mode 100644 backup-website/docs/pixark/metadata.json create mode 100644 backup-website/docs/pvkii/icon.png create mode 100644 backup-website/docs/pvkii/index.php create mode 100644 backup-website/docs/pvkii/metadata.json create mode 100644 backup-website/docs/quake3/icon.png create mode 100644 backup-website/docs/quake3/index.php create mode 100644 backup-website/docs/quake3/metadata.json create mode 100644 backup-website/docs/quake4/icon.png create mode 100644 backup-website/docs/quake4/index.php create mode 100644 backup-website/docs/quake4/metadata.json create mode 100644 backup-website/docs/redorchestra2/icon.png create mode 100644 backup-website/docs/redorchestra2/index.php create mode 100644 backup-website/docs/redorchestra2/metadata.json create mode 100644 backup-website/docs/reignofkings/icon.png create mode 100644 backup-website/docs/reignofkings/index.php create mode 100644 backup-website/docs/reignofkings/metadata.json create mode 100644 backup-website/docs/ricochet/icon.png create mode 100644 backup-website/docs/ricochet/index.php create mode 100644 backup-website/docs/ricochet/metadata.json create mode 100644 backup-website/docs/risingstorm2/icon.png create mode 100644 backup-website/docs/risingstorm2/index.php create mode 100644 backup-website/docs/risingstorm2/metadata.json create mode 100644 backup-website/docs/roadkill/icon.png create mode 100644 backup-website/docs/roadkill/index.php create mode 100644 backup-website/docs/roadkill/metadata.json create mode 100644 backup-website/docs/rorserver/icon.png create mode 100644 backup-website/docs/rorserver/index.php create mode 100644 backup-website/docs/rorserver/metadata.json create mode 100644 backup-website/docs/rust/icon.png create mode 100644 backup-website/docs/rust/index.php create mode 100644 backup-website/docs/rust/index_old.php create mode 100644 backup-website/docs/rust/metadata.json create mode 100644 backup-website/docs/sanandreasmp/icon.png create mode 100644 backup-website/docs/sanandreasmp/index.php create mode 100644 backup-website/docs/sanandreasmp/metadata.json create mode 100644 backup-website/docs/serioussamhdfe/icon.png create mode 100644 backup-website/docs/serioussamhdfe/index.php create mode 100644 backup-website/docs/serioussamhdfe/metadata.json create mode 100644 backup-website/docs/serioussamhdse/icon.png create mode 100644 backup-website/docs/serioussamhdse/index.php create mode 100644 backup-website/docs/serioussamhdse/metadata.json create mode 100644 backup-website/docs/shoutcast/icon.png create mode 100644 backup-website/docs/shoutcast/index.php create mode 100644 backup-website/docs/shoutcast/metadata.json create mode 100644 backup-website/docs/shoutcast_bot/icon.png create mode 100644 backup-website/docs/shoutcast_bot/index.php create mode 100644 backup-website/docs/shoutcast_bot/metadata.json create mode 100644 backup-website/docs/sinusbot/icon.png create mode 100644 backup-website/docs/sinusbot/index.php create mode 100644 backup-website/docs/sinusbot/metadata.json create mode 100644 backup-website/docs/smashball/icon.png create mode 100644 backup-website/docs/smashball/index.php create mode 100644 backup-website/docs/smashball/metadata.json create mode 100644 backup-website/docs/smokinguns/icon.png create mode 100644 backup-website/docs/smokinguns/index.php create mode 100644 backup-website/docs/smokinguns/metadata.json create mode 100644 backup-website/docs/sms/icon.png create mode 100644 backup-website/docs/sms/index.php create mode 100644 backup-website/docs/sms/metadata.json create mode 100644 backup-website/docs/sniperelitev2/icon.png create mode 100644 backup-website/docs/sniperelitev2/index.php create mode 100644 backup-website/docs/sniperelitev2/metadata.json create mode 100644 backup-website/docs/soldatserver/icon.png create mode 100644 backup-website/docs/soldatserver/index.php create mode 100644 backup-website/docs/soldatserver/metadata.json create mode 100644 backup-website/docs/space_engineers/icon.jpg create mode 100644 backup-website/docs/space_engineers/index.php create mode 100644 backup-website/docs/space_engineers/metadata.json create mode 100644 backup-website/docs/spigotmc/icon.png create mode 100644 backup-website/docs/spigotmc/index.php create mode 100644 backup-website/docs/spigotmc/metadata.json create mode 100644 backup-website/docs/spunkybot/icon.jpg create mode 100644 backup-website/docs/spunkybot/index.php create mode 100644 backup-website/docs/spunkybot/metadata.json create mode 100644 backup-website/docs/squad/icon.jpg create mode 100644 backup-website/docs/squad/index.php create mode 100644 backup-website/docs/squad/metadata.json create mode 100644 backup-website/docs/starbound/icon.jpg create mode 100644 backup-website/docs/starbound/index.php create mode 100644 backup-website/docs/starbound/metadata.json create mode 100644 backup-website/docs/stationeers/icon.jpg create mode 100644 backup-website/docs/stationeers/index.php create mode 100644 backup-website/docs/stationeers/metadata.json create mode 100644 backup-website/docs/synergy/icon.png create mode 100644 backup-website/docs/synergy/index.php create mode 100644 backup-website/docs/synergy/metadata.json create mode 100644 backup-website/docs/teamspeak2/icon.png create mode 100644 backup-website/docs/teamspeak2/index.php create mode 100644 backup-website/docs/teamspeak2/metadata.json create mode 100644 backup-website/docs/teamspeak3/icon.png create mode 100644 backup-website/docs/teamspeak3/index.php create mode 100644 backup-website/docs/teamspeak3/metadata.json create mode 100644 backup-website/docs/terraria/icon.jpg create mode 100644 backup-website/docs/terraria/index.php create mode 100644 backup-website/docs/terraria/metadata.json create mode 100644 backup-website/docs/tf2/icon.jpg create mode 100644 backup-website/docs/tf2/index.php create mode 100644 backup-website/docs/tf2/index_old.php create mode 100644 backup-website/docs/tf2/metadata.json create mode 100644 backup-website/docs/tfc/icon.png create mode 100644 backup-website/docs/tfc/index.php create mode 100644 backup-website/docs/tfc/metadata.json create mode 100644 backup-website/docs/theforest/icon.png create mode 100644 backup-website/docs/theforest/index.php create mode 100644 backup-website/docs/theforest/metadata.json create mode 100644 backup-website/docs/trackmanianations/icon.png create mode 100644 backup-website/docs/trackmanianations/index.php create mode 100644 backup-website/docs/trackmanianations/metadata.json create mode 100644 backup-website/docs/trackmanianf/icon.png create mode 100644 backup-website/docs/trackmanianf/index.php create mode 100644 backup-website/docs/trackmanianf/metadata.json create mode 100644 backup-website/docs/unturned/icon.jpg create mode 100644 backup-website/docs/unturned/index.php create mode 100644 backup-website/docs/unturned/metadata.json create mode 100644 backup-website/docs/urt/icon.jpg create mode 100644 backup-website/docs/urt/index.php create mode 100644 backup-website/docs/urt/metadata.json create mode 100644 backup-website/docs/ut2004/icon.png create mode 100644 backup-website/docs/ut2004/index.php create mode 100644 backup-website/docs/ut2004/metadata.json create mode 100644 backup-website/docs/ut3/icon.png create mode 100644 backup-website/docs/ut3/index.php create mode 100644 backup-website/docs/ut3/metadata.json create mode 100644 backup-website/docs/ut99/icon.png create mode 100644 backup-website/docs/ut99/index.php create mode 100644 backup-website/docs/ut99/metadata.json create mode 100644 backup-website/docs/valheim/icon.jpg create mode 100644 backup-website/docs/valheim/index.php create mode 100644 backup-website/docs/valheim/metadata.json create mode 100644 backup-website/docs/vbox/icon.png create mode 100644 backup-website/docs/vbox/index.php create mode 100644 backup-website/docs/vbox/metadata.json create mode 100644 backup-website/docs/ventrilo/icon.png create mode 100644 backup-website/docs/ventrilo/index.php create mode 100644 backup-website/docs/ventrilo/metadata.json create mode 100644 backup-website/docs/vicecitymp/icon.png create mode 100644 backup-website/docs/vicecitymp/index.php create mode 100644 backup-website/docs/vicecitymp/metadata.json create mode 100644 backup-website/docs/warsow/icon.png create mode 100644 backup-website/docs/warsow/index.php create mode 100644 backup-website/docs/warsow/metadata.json create mode 100644 backup-website/docs/wolfrtcw_1-4/icon.png create mode 100644 backup-website/docs/wolfrtcw_1-4/index.php create mode 100644 backup-website/docs/wolfrtcw_1-4/metadata.json create mode 100644 backup-website/docs/wreckfest/icon.png create mode 100644 backup-website/docs/wreckfest/index.php create mode 100644 backup-website/docs/wreckfest/metadata.json create mode 100644 backup-website/docs/wurmu/icon.jpg create mode 100644 backup-website/docs/wurmu/index.php create mode 100644 backup-website/docs/wurmu/metadata.json create mode 100644 backup-website/docs/xonotic/icon.png create mode 100644 backup-website/docs/xonotic/index.php create mode 100644 backup-website/docs/xonotic/metadata.json create mode 100644 backup-website/docs/zps/icon.png create mode 100644 backup-website/docs/zps/index.php create mode 100644 backup-website/docs/zps/metadata.json create mode 100644 backup-website/error_log create mode 100644 backup-website/fix_invoices_table_columns.sql create mode 100644 backup-website/forgot_password.php create mode 100644 backup-website/images/banner.png create mode 100644 backup-website/images/bf3_the_russian.jpg create mode 100644 backup-website/images/dark.jpg create mode 100644 backup-website/images/featured/7dtd.jpg create mode 100644 backup-website/images/featured/arkse.jpg create mode 100644 backup-website/images/featured/arma2_operation_arrowhead.jpg create mode 100644 backup-website/images/featured/arma_3.jpg create mode 100644 backup-website/images/featured/cs_go.jpg create mode 100644 backup-website/images/featured/day_z.jpg create mode 100644 backup-website/images/featured/dayz_epochmod.jpg create mode 100644 backup-website/images/featured/dayz_mod.jpg create mode 100644 backup-website/images/featured/eurotruck2.jpg create mode 100644 backup-website/images/featured/fistful_of_frags.jpg create mode 100644 backup-website/images/featured/insurgency.jpg create mode 100644 backup-website/images/featured/insurgency_sandstorm.jpg create mode 100644 backup-website/images/featured/minecraft.jpg create mode 100644 backup-website/images/games/7dtd.jpg create mode 100644 backup-website/images/games/arkse.jpg create mode 100644 backup-website/images/games/arma2.jpg create mode 100644 backup-website/images/games/arma2_operation_arrowhead.jpg create mode 100644 backup-website/images/games/arma_3.jpg create mode 100644 backup-website/images/games/asseto.jpg create mode 100644 backup-website/images/games/avorion.jpg create mode 100644 backup-website/images/games/brainbread_2.jpg create mode 100644 backup-website/images/games/chivalry.jpg create mode 100644 backup-website/images/games/citadel.jpg create mode 100644 backup-website/images/games/colonysurvival.jpg create mode 100644 backup-website/images/games/conanexiles.jpg create mode 100644 backup-website/images/games/cs_go.jpg create mode 100644 backup-website/images/games/cstrike.jpg create mode 100644 backup-website/images/games/cstrikesource.jpg create mode 100644 backup-website/images/games/day_of_defeat_source.jpg create mode 100644 backup-website/images/games/day_z.jpg create mode 100644 backup-website/images/games/dayz_epochmod.jpg create mode 100644 backup-website/images/games/dayz_mod.jpg create mode 100644 backup-website/images/games/deathmatch_classic.jpg create mode 100644 backup-website/images/games/dst.jpg create mode 100644 backup-website/images/games/eco.jpg create mode 100644 backup-website/images/games/eurotruck2.jpg create mode 100644 backup-website/images/games/fistful_of_frags.jpg create mode 100644 backup-website/images/games/garrys_mod.jpg create mode 100644 backup-website/images/games/half-life2_deathmatch.jpg create mode 100644 backup-website/images/games/harsh.jpg create mode 100644 backup-website/images/games/hurt_world.jpg create mode 100644 backup-website/images/games/insurgency.jpg create mode 100644 backup-website/images/games/insurgency_sandstorm.jpg create mode 100644 backup-website/images/games/killing_floor.jpg create mode 100644 backup-website/images/games/killing_floor_2.jpg create mode 100644 backup-website/images/games/left_4_dead.jpg create mode 100644 backup-website/images/games/left_4_dead_2.jpg create mode 100644 backup-website/images/games/minecraft.jpg create mode 100644 backup-website/images/games/miscreated_server.jpg create mode 100644 backup-website/images/games/mordhau.jpg create mode 100644 backup-website/images/games/nomoreroominhell.jpg create mode 100644 backup-website/images/games/ootow.jpg create mode 100644 backup-website/images/games/rust_header.jpg create mode 100644 backup-website/images/games/scp.jpg create mode 100644 backup-website/images/games/squad.jpg create mode 100644 backup-website/images/games/starbound.jpg create mode 100644 backup-website/images/games/stationeers.jpg create mode 100644 backup-website/images/games/team_fortress_2.jpg create mode 100644 backup-website/images/games/terraria.jpg create mode 100644 backup-website/images/games/urt.jpg create mode 100644 backup-website/images/games/valheim.jpg create mode 100644 backup-website/images/games/wurmu.jpg create mode 100644 backup-website/images/logo-sm.png create mode 100644 backup-website/images/logo.jpg create mode 100644 backup-website/images/logo.png create mode 100644 backup-website/includes/README.md create mode 100644 backup-website/includes/admin_auth.php create mode 100644 backup-website/includes/cart_helper.php create mode 100644 backup-website/includes/config.inc.php create mode 100644 backup-website/includes/config.inc.php.orig create mode 100644 backup-website/includes/footer.php create mode 100644 backup-website/includes/log.php create mode 100644 backup-website/includes/login_required.php create mode 100644 backup-website/includes/menu.php create mode 100644 backup-website/includes/payment_processor.php create mode 100644 backup-website/includes/top.php create mode 100644 backup-website/index.php create mode 100644 backup-website/invoices.php create mode 100644 backup-website/logfile.txt create mode 100644 backup-website/login.php create mode 100644 backup-website/logout.php create mode 100644 backup-website/logs/payment_capture.log create mode 100644 backup-website/migration_to_invoices.sql create mode 100644 backup-website/module.php create mode 100644 backup-website/my_account.php create mode 100644 backup-website/my_servers.php create mode 100644 backup-website/order.php create mode 100644 backup-website/payment_cancel.php create mode 100644 backup-website/payment_success.php create mode 100644 backup-website/privacy.php create mode 100644 backup-website/register.php create mode 100644 backup-website/renew_server.php create mode 100644 backup-website/reset_password.php create mode 100644 backup-website/return.php create mode 100644 backup-website/server_status.php create mode 100644 backup-website/serverlist.php create mode 100644 backup-website/test_db_connection.php create mode 100644 backup-website/timestamp.txt create mode 100644 backup-website/tools/check_db_user.php create mode 100644 backup-website/tools/check_invoices_redirect.php create mode 100644 backup-website/tools/check_logout_redirect.php create mode 100644 backup-website/tools/debug_invoices_redirect.php create mode 100644 backup-website/tools/simulate_webhook.php create mode 100644 backup-website/tos.php create mode 100644 backup-website/webhook.php create mode 100644 backup-website/well-known.zip create mode 100644 docs/modules/website_billing_rebuild.md diff --git a/Panel/modules/website/README.md b/Panel/modules/website/README.md index 459f3fa4..42e91cad 100644 --- a/Panel/modules/website/README.md +++ b/Panel/modules/website/README.md @@ -15,15 +15,42 @@ This module is the public Gameservers.World sales and documentation website. Panel/modules/website/ index.php serverlist.php + order.php cart.php + checkout.php + payment_success.php + payment_cancel.php docs.php login.php + register.php + forgot_password.php + reset_password.php + account.php + orders.php + invoices.php + my_servers.php + staff.php + staff_services.php + staff_locations.php + staff_coupons.php + staff_orders.php + staff_invoices.php + staff_payments.php + staff_paypal.php + staff_settings.php + staff_provisioning.php + staff_migrations.php + webhook.php pricing.php locations.php support.php doc_asset.php + api/ + create_order.php + capture_order.php includes/ bootstrap.php + billing.php footer.php header.php navigation.php @@ -57,7 +84,7 @@ The website uses a central bootstrap instead of scattered relative paths. - `website_order_url(1)` - `documentation_url('minecraft')` -## Billing and database behavior +## Billing, database, and staff behavior The public site does not include `Panel/modules/billing/includes/config.inc.php` directly. @@ -74,6 +101,20 @@ Effects: - `serverlist.php` shows a clean fallback message instead of a fatal include error - shared navigation never crashes because billing config is missing +Sales and billing tables are installed through the staff migration runner: + +- `staff_migrations.php` + +The runner is idempotent and uses the current configured Panel table prefix. It +creates invoice, order, payment, coupon, password-reset, PayPal webhook, website +settings, and provisioning-attempt tables when missing. It also adds missing +catalog columns to an existing `billing_services` table. + +Website staff pages are separate from GSP Panel administration. They manage +website sales, catalog, pricing, coupons, invoices, payments, PayPal settings, +and the paid-order provisioning queue. Access currently requires a Panel admin +account. + ## Shared Accounts The Panel user table is the identity source for the website. Website login checks @@ -106,6 +147,23 @@ and customer confirmation. Payment approval and final server provisioning remain server-side responsibilities; browser requests must not call private provisioning methods directly. +Checkout creates invoice/order records only after login or registration. The +anonymous cart remains in the website session until that point. PayPal order +creation and capture are handled through `api/create_order.php` and +`api/capture_order.php`; `webhook.php` verifies PayPal webhook signatures and +deduplicates events. + +PayPal credentials must not be committed to source. Preferred runtime settings: + +- `GSP_WEBSITE_PAYPAL_CLIENT_ID` +- `GSP_WEBSITE_PAYPAL_CLIENT_SECRET` +- `GSP_WEBSITE_PAYPAL_WEBHOOK_ID` + +The staff PayPal page can store fallback settings in `website_settings`, but +secrets are masked after save. + +More detail: `docs/modules/website_billing_rebuild.md`. + ## Documentation source Customer documentation is read from the existing billing docs directory: diff --git a/Panel/modules/website/admin.php b/Panel/modules/website/admin.php new file mode 100644 index 00000000..1ad65bc5 --- /dev/null +++ b/Panel/modules/website/admin.php @@ -0,0 +1,8 @@ + 'login_required']); + exit; +} + +$input = json_decode((string)file_get_contents('php://input'), true); +$invoiceId = (int)($input['invoice_id'] ?? 0); +$paypalOrderId = trim((string)($input['order_id'] ?? '')); +$config = website_paypal_config(); +$db = website_db(); +if (!$config['enabled'] || $paypalOrderId === '' || !$db instanceof mysqli) { + http_response_code(400); + echo json_encode(['error' => 'invalid_request']); + exit; +} + +$invoiceTable = website_table('billing_invoices'); +$uid = (int)$user['user_id']; +$stmt = $db->prepare("SELECT * FROM `{$invoiceTable}` WHERE `invoice_id` = ? AND `user_id` = ? AND `status` = 'due' LIMIT 1"); +$stmt->bind_param('ii', $invoiceId, $uid); +$stmt->execute(); +$invoice = $stmt->get_result()->fetch_assoc(); +$stmt->close(); +if (!is_array($invoice) || (string)($invoice['paypal_order_id'] ?? '') !== $paypalOrderId) { + http_response_code(404); + echo json_encode(['error' => 'invoice_not_found']); + exit; +} + +$access = website_paypal_oauth($config); +if (!$access) { + http_response_code(502); + echo json_encode(['error' => 'paypal_oauth_failed']); + exit; +} + +$ch = curl_init(website_paypal_api_base($config) . '/v2/checkout/orders/' . rawurlencode($paypalOrderId) . '/capture'); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $access], + CURLOPT_TIMEOUT => 30, +]); +$response = curl_exec($ch); +$http = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +if (($http !== 200 && $http !== 201) || !is_string($response)) { + website_log('PayPal capture failed for invoice ' . $invoiceId); + http_response_code(502); + echo json_encode(['error' => 'paypal_capture_failed']); + exit; +} + +$json = json_decode($response, true); +$status = (string)($json['status'] ?? ''); +$capture = $json['purchase_units'][0]['payments']['captures'][0] ?? []; +$captureId = (string)($capture['id'] ?? ''); +$payerEmail = (string)($json['payer']['email_address'] ?? ''); +$paidAmount = (float)($capture['amount']['value'] ?? 0); +$currency = (string)($capture['amount']['currency_code'] ?? ''); + +if ($status !== 'COMPLETED' || $captureId === '' || abs($paidAmount - (float)$invoice['amount']) > 0.01 || $currency !== (string)$invoice['currency']) { + http_response_code(409); + echo json_encode(['error' => 'payment_not_verified']); + exit; +} + +website_mark_invoice_paid($invoiceId, 'paypal', $paypalOrderId, $captureId, $payerEmail, ['paypal_status' => $status]); +echo json_encode(['status' => 'COMPLETED', 'invoice_id' => $invoiceId]); diff --git a/Panel/modules/website/api/create_order.php b/Panel/modules/website/api/create_order.php new file mode 100644 index 00000000..0dd132c4 --- /dev/null +++ b/Panel/modules/website/api/create_order.php @@ -0,0 +1,97 @@ + 'login_required']); + exit; +} + +$input = json_decode((string)file_get_contents('php://input'), true); +$invoiceId = (int)($input['invoice_id'] ?? 0); +$db = website_db(); +$config = website_paypal_config(); + +if (!$config['enabled'] || $config['client_id'] === '' || $config['client_secret'] === '') { + http_response_code(503); + echo json_encode(['error' => 'paypal_not_configured']); + exit; +} +if (!$db instanceof mysqli || $invoiceId <= 0) { + http_response_code(400); + echo json_encode(['error' => 'invalid_invoice']); + exit; +} + +$invoiceTable = website_table('billing_invoices'); +$stmt = $db->prepare("SELECT * FROM `{$invoiceTable}` WHERE `invoice_id` = ? AND `user_id` = ? AND `status` = 'due' LIMIT 1"); +$uid = (int)$user['user_id']; +$stmt->bind_param('ii', $invoiceId, $uid); +$stmt->execute(); +$invoice = $stmt->get_result()->fetch_assoc(); +$stmt->close(); +if (!is_array($invoice)) { + http_response_code(404); + echo json_encode(['error' => 'invoice_not_found']); + exit; +} + +$access = website_paypal_oauth($config); +if (!$access) { + http_response_code(502); + echo json_encode(['error' => 'paypal_oauth_failed']); + exit; +} + +$amount = number_format((float)$invoice['amount'], 2, '.', ''); +$currency = (string)$invoice['currency']; +$body = [ + 'intent' => 'CAPTURE', + 'purchase_units' => [[ + 'invoice_id' => 'GSW-' . $invoiceId, + 'custom_id' => (string)$invoiceId, + 'description' => $config['description_prefix'] . ' #' . $invoiceId, + 'amount' => ['currency_code' => $currency, 'value' => $amount], + ]], + 'application_context' => [ + 'return_url' => website_canonical_url('payment_success.php?invoice_id=' . $invoiceId), + 'cancel_url' => website_canonical_url('payment_cancel.php?invoice_id=' . $invoiceId), + 'user_action' => 'PAY_NOW', + ], +]; + +$ch = curl_init(website_paypal_api_base($config) . '/v2/checkout/orders'); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($body), + CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $access], + CURLOPT_TIMEOUT => 20, +]); +$response = curl_exec($ch); +$http = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +if ($http !== 201 || !is_string($response)) { + website_log('PayPal order create failed for invoice ' . $invoiceId); + http_response_code(502); + echo json_encode(['error' => 'paypal_order_failed']); + exit; +} + +$json = json_decode($response, true); +$paypalOrderId = (string)($json['id'] ?? ''); +if ($paypalOrderId !== '') { + $stmt = $db->prepare("UPDATE `{$invoiceTable}` SET `paypal_order_id` = ? WHERE `invoice_id` = ?"); + $stmt->bind_param('si', $paypalOrderId, $invoiceId); + $stmt->execute(); + $stmt->close(); +} + +echo json_encode(['id' => $paypalOrderId]); diff --git a/Panel/modules/website/cart.php b/Panel/modules/website/cart.php index 63b38ad7..dd9819e2 100644 --- a/Panel/modules/website/cart.php +++ b/Panel/modules/website/cart.php @@ -9,13 +9,13 @@ $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = (string)($_POST['action'] ?? ''); - if ($action === 'remove') { + if (!website_verify_csrf()) { + $error = 'Your form expired. Please try again.'; + } elseif ($action === 'remove') { website_cart_remove((string)($_POST['cart_key'] ?? '')); header('Location: ' . website_cart_url(), true, 302); exit; - } - - if ($action === 'checkout') { + } elseif ($action === 'checkout') { if (website_cart_count() === 0) { $error = 'Your cart is empty.'; } elseif (!website_is_logged_in()) { @@ -24,8 +24,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { header('Location: ' . website_login_url('cart.php?checkout=1'), true, 302); exit; } else { - website_log_activity('Website checkout requested', (int)($_SESSION['website_user_id'] ?? 0), 'checkout_requested'); - $message = 'Checkout is ready for account validation, but the payment gateway is not connected in this repository checkout. Please contact support to complete this order.'; + $invoiceId = website_create_invoice_from_cart((int)$_SESSION['website_user_id']); + if ($invoiceId === null) { + $error = 'We could not create an invoice from this cart. Please contact support.'; + } else { + website_log_activity('Website checkout invoice created #' . $invoiceId, (int)$_SESSION['website_user_id'], 'checkout_requested'); + header('Location: ' . website_url('checkout.php?invoice_id=' . $invoiceId), true, 302); + exit; + } } } } @@ -39,7 +45,13 @@ if (isset($_GET['checkout']) && (string)$_GET['checkout'] === '1') { header('Location: ' . website_login_url('cart.php?checkout=1'), true, 302); exit; } else { - $message = 'You are logged in and your cart is preserved. Payment checkout still needs the active payment runtime before public orders can be completed.'; + $invoiceId = website_create_invoice_from_cart((int)$_SESSION['website_user_id']); + if ($invoiceId === null) { + $error = 'We could not create an invoice from this cart. Please contact support.'; + } else { + header('Location: ' . website_url('checkout.php?invoice_id=' . $invoiceId), true, 302); + exit; + } } } diff --git a/Panel/modules/website/checkout.php b/Panel/modules/website/checkout.php new file mode 100644 index 00000000..663ab6ec --- /dev/null +++ b/Panel/modules/website/checkout.php @@ -0,0 +1,46 @@ + 0 && website_table_exists(website_table('billing_invoices'))) { + $invoiceTable = website_table('billing_invoices'); + $orderTable = website_table('billing_orders'); + $stmt = $db->prepare("SELECT * FROM `{$invoiceTable}` WHERE `invoice_id` = ? AND `user_id` = ? LIMIT 1"); + if ($stmt) { + $uid = (int)$user['user_id']; + $stmt->bind_param('ii', $invoiceId, $uid); + $stmt->execute(); + $invoice = $stmt->get_result()->fetch_assoc(); + $stmt->close(); + } + if ($invoice && website_table_exists($orderTable)) { + $stmt = $db->prepare("SELECT * FROM `{$orderTable}` WHERE `invoice_id` = ? ORDER BY `order_id` ASC"); + if ($stmt) { + $stmt->bind_param('i', $invoiceId); + $stmt->execute(); + $result = $stmt->get_result(); + while ($result instanceof mysqli_result && ($row = $result->fetch_assoc())) { + $orders[] = $row; + } + $stmt->close(); + } + } +} + +website_render('checkout.php', [ + 'activePage' => 'cart', + 'pageTitle' => 'Checkout - Gameservers.World', + 'metaDescription' => 'Pay a Gameservers.World invoice.', + 'canonicalPath' => 'checkout.php', + 'invoice' => $invoice, + 'orders' => $orders, + 'paypalConfig' => website_paypal_config(), +]); diff --git a/Panel/modules/website/forgot_password.php b/Panel/modules/website/forgot_password.php new file mode 100644 index 00000000..1492fe73 --- /dev/null +++ b/Panel/modules/website/forgot_password.php @@ -0,0 +1,54 @@ +prepare("SELECT `user_id`, `users_email` FROM `{$usersTable}` WHERE `users_login` = ? OR `users_email` = ? LIMIT 1"); + if ($stmt) { + $stmt->bind_param('ss', $identifier, $identifier); + $stmt->execute(); + $user = $stmt->get_result()->fetch_assoc(); + $stmt->close(); + if (is_array($user)) { + $rawToken = bin2hex(random_bytes(32)); + $tokenHash = hash('sha256', $rawToken); + $resetTable = website_table('password_reset_tokens'); + $userId = (int)$user['user_id']; + $ip = website_client_ip(); + $db->query("DELETE FROM `{$resetTable}` WHERE `user_id` = {$userId} AND `used_at` IS NULL"); + $insert = $db->prepare("INSERT INTO `{$resetTable}` (`user_id`, `token_hash`, `expires_at`, `created_at`, `originating_ip`) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 1 HOUR), NOW(), ?)"); + if ($insert) { + $insert->bind_param('iss', $userId, $tokenHash, $ip); + $insert->execute(); + $insert->close(); + website_log_activity('Website password reset requested', $userId, 'password_reset_requested'); + $resetUrl = website_canonical_url('reset_password.php?token=' . rawurlencode($rawToken)); + @mail((string)$user['users_email'], 'Gameservers.World password reset', "Use this link to reset your password:\n\n" . $resetUrl . "\n\nThis link expires in 1 hour."); + } + } + } + } + } +} + +website_render('forgot_password.php', [ + 'activePage' => 'account', + 'pageTitle' => 'Forgot Password - Gameservers.World', + 'metaDescription' => 'Reset your Gameservers.World password.', + 'canonicalPath' => 'forgot_password.php', + 'message' => $message, + 'error' => $error, +]); diff --git a/Panel/modules/website/includes/billing.php b/Panel/modules/website/includes/billing.php new file mode 100644 index 00000000..fc407001 --- /dev/null +++ b/Panel/modules/website/includes/billing.php @@ -0,0 +1,538 @@ +'; +} + +function website_verify_csrf(): bool +{ + website_start_session(); + $token = (string)($_POST['csrf_token'] ?? ''); + return $token !== '' && hash_equals((string)($_SESSION['website_csrf_token'] ?? ''), $token); +} + +function website_require_login(string $returnPath = 'account.php'): ?array +{ + $user = website_current_user(); + if ($user === null) { + $_SESSION['website_login_return'] = website_safe_return_path($returnPath, 'account.php'); + header('Location: ' . website_login_url($returnPath), true, 302); + exit; + } + return $user; +} + +function website_require_staff(): array +{ + $user = website_require_login('staff.php'); + if ($user === null || !website_current_user_is_staff()) { + http_response_code(403); + website_render('message.php', [ + 'activePage' => 'account', + 'pageTitle' => 'Access Denied - Gameservers.World', + 'heading' => 'Access Denied', + 'message' => 'This page is available only to authorized website staff.', + ]); + exit; + } + return $user; +} + +function website_column_exists(string $tableName, string $columnName): bool +{ + return isset(website_table_columns($tableName)[$columnName]); +} + +function website_billing_migrations(): array +{ + $prefix = website_table_prefix(); + return [ + "CREATE TABLE IF NOT EXISTS `{$prefix}billing_invoices` ( + `invoice_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` INT NOT NULL, + `status` VARCHAR(24) NOT NULL DEFAULT 'due', + `amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00, + `currency` CHAR(3) NOT NULL DEFAULT 'USD', + `description` VARCHAR(255) DEFAULT NULL, + `invoice_date` DATETIME NOT NULL, + `due_date` DATETIME DEFAULT NULL, + `paid_date` DATETIME DEFAULT NULL, + `payment_method` VARCHAR(40) DEFAULT NULL, + `payment_txid` VARCHAR(128) DEFAULT NULL, + `paypal_order_id` VARCHAR(128) DEFAULT NULL, + `paypal_capture_id` VARCHAR(128) DEFAULT NULL, + `payer_email` VARCHAR(255) DEFAULT NULL, + `coupon_id` INT DEFAULT NULL, + `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00, + `order_id` INT DEFAULT NULL, + `metadata_json` TEXT DEFAULT NULL, + PRIMARY KEY (`invoice_id`), + KEY `idx_invoice_user_status` (`user_id`, `status`), + KEY `idx_invoice_payment` (`paypal_order_id`, `paypal_capture_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", + "CREATE TABLE IF NOT EXISTS `{$prefix}billing_orders` ( + `order_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `invoice_id` INT UNSIGNED DEFAULT NULL, + `user_id` INT NOT NULL, + `service_id` INT NOT NULL, + `home_id` INT DEFAULT NULL, + `home_name` VARCHAR(120) NOT NULL, + `remote_server_id` INT DEFAULT NULL, + `max_players` INT NOT NULL DEFAULT 0, + `qty` INT NOT NULL DEFAULT 1, + `invoice_duration` VARCHAR(24) NOT NULL DEFAULT 'month', + `price` DECIMAL(10,2) NOT NULL DEFAULT 0.00, + `status` VARCHAR(32) NOT NULL DEFAULT 'paid', + `order_date` DATETIME NOT NULL, + `end_date` DATETIME DEFAULT NULL, + `payment_txid` VARCHAR(128) DEFAULT NULL, + `paid_ts` DATETIME DEFAULT NULL, + `provisioning_claim` VARCHAR(64) DEFAULT NULL, + `provisioning_error` TEXT DEFAULT NULL, + `metadata_json` TEXT DEFAULT NULL, + PRIMARY KEY (`order_id`), + UNIQUE KEY `uniq_invoice_service` (`invoice_id`, `service_id`, `home_name`), + KEY `idx_order_user_status` (`user_id`, `status`), + KEY `idx_order_home` (`home_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", + "CREATE TABLE IF NOT EXISTS `{$prefix}billing_payments` ( + `payment_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `invoice_id` INT UNSIGNED DEFAULT NULL, + `user_id` INT DEFAULT NULL, + `provider` VARCHAR(40) NOT NULL, + `provider_order_id` VARCHAR(128) DEFAULT NULL, + `provider_capture_id` VARCHAR(128) DEFAULT NULL, + `amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00, + `currency` CHAR(3) NOT NULL DEFAULT 'USD', + `status` VARCHAR(40) NOT NULL, + `payer_email` VARCHAR(255) DEFAULT NULL, + `created_at` DATETIME NOT NULL, + `metadata_json` TEXT DEFAULT NULL, + PRIMARY KEY (`payment_id`), + UNIQUE KEY `uniq_provider_capture` (`provider`, `provider_capture_id`), + KEY `idx_payment_invoice` (`invoice_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", + "CREATE TABLE IF NOT EXISTS `{$prefix}billing_coupons` ( + `coupon_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `code` VARCHAR(64) NOT NULL, + `name` VARCHAR(120) NOT NULL, + `description` TEXT DEFAULT NULL, + `discount_type` VARCHAR(16) NOT NULL DEFAULT 'percent', + `discount_value` DECIMAL(10,2) NOT NULL DEFAULT 0.00, + `is_active` TINYINT(1) NOT NULL DEFAULT 1, + `starts_at` DATETIME DEFAULT NULL, + `expires` DATETIME DEFAULT NULL, + `max_uses` INT DEFAULT NULL, + `current_uses` INT NOT NULL DEFAULT 0, + `minimum_amount` DECIMAL(10,2) DEFAULT NULL, + `service_filter_json` TEXT DEFAULT NULL, + `created_at` DATETIME NOT NULL, + PRIMARY KEY (`coupon_id`), + UNIQUE KEY `uniq_coupon_code` (`code`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", + "CREATE TABLE IF NOT EXISTS `{$prefix}website_settings` ( + `setting_key` VARCHAR(120) NOT NULL, + `setting_value` TEXT DEFAULT NULL, + `is_secret` TINYINT(1) NOT NULL DEFAULT 0, + `updated_at` DATETIME NOT NULL, + PRIMARY KEY (`setting_key`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", + "CREATE TABLE IF NOT EXISTS `{$prefix}password_reset_tokens` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` INT NOT NULL, + `token_hash` CHAR(64) NOT NULL, + `expires_at` DATETIME NOT NULL, + `used_at` DATETIME DEFAULT NULL, + `created_at` DATETIME NOT NULL, + `originating_ip` VARCHAR(64) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_reset_token_hash` (`token_hash`), + KEY `idx_reset_user` (`user_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", + "CREATE TABLE IF NOT EXISTS `{$prefix}payment_webhook_events` ( + `event_id` VARCHAR(128) NOT NULL, + `provider` VARCHAR(40) NOT NULL, + `event_type` VARCHAR(120) DEFAULT NULL, + `received_at` DATETIME NOT NULL, + `processed_at` DATETIME DEFAULT NULL, + `status` VARCHAR(40) NOT NULL DEFAULT 'received', + `metadata_json` TEXT DEFAULT NULL, + PRIMARY KEY (`event_id`, `provider`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", + "CREATE TABLE IF NOT EXISTS `{$prefix}provisioning_attempts` ( + `attempt_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `order_id` INT UNSIGNED NOT NULL, + `status` VARCHAR(40) NOT NULL, + `message` TEXT DEFAULT NULL, + `created_at` DATETIME NOT NULL, + PRIMARY KEY (`attempt_id`), + KEY `idx_provision_order` (`order_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", + ]; +} + +function website_run_billing_migrations(): array +{ + $db = website_db(); + if (!$db instanceof mysqli) { + return ['Database connection is unavailable.']; + } + + $errors = []; + foreach (website_billing_migrations() as $sql) { + if (!$db->query($sql)) { + $errors[] = $db->error; + } + } + $serviceTable = website_table('billing_services'); + if (website_table_exists($serviceTable)) { + $serviceColumns = [ + 'description' => 'TEXT DEFAULT NULL', + 'img_url' => 'VARCHAR(255) DEFAULT NULL', + 'price_monthly' => 'DECIMAL(10,2) NOT NULL DEFAULT 0.00', + 'slot_min_qty' => 'INT NOT NULL DEFAULT 16', + 'slot_max_qty' => 'INT NOT NULL DEFAULT 0', + 'enabled' => 'TINYINT(1) NOT NULL DEFAULT 1', + 'remote_server_id' => 'VARCHAR(255) DEFAULT NULL', + ]; + $existing = website_table_columns($serviceTable); + foreach ($serviceColumns as $column => $definition) { + if (isset($existing[$column])) { + continue; + } + $safeTable = str_replace('`', '``', $serviceTable); + $safeColumn = str_replace('`', '``', $column); + if (!$db->query("ALTER TABLE `{$safeTable}` ADD COLUMN `{$safeColumn}` {$definition}")) { + $errors[] = $db->error; + } + } + } + return $errors; +} + +function website_setting(string $key, ?string $default = null): ?string +{ + $db = website_db(); + if (!$db instanceof mysqli || !website_table_exists(website_table('website_settings'))) { + return $default; + } + $table = website_table('website_settings'); + $stmt = $db->prepare("SELECT `setting_value` FROM `{$table}` WHERE `setting_key` = ? LIMIT 1"); + if (!$stmt) { + return $default; + } + $stmt->bind_param('s', $key); + $stmt->execute(); + $result = $stmt->get_result(); + $row = $result instanceof mysqli_result ? $result->fetch_assoc() : null; + $stmt->close(); + return is_array($row) ? (string)$row['setting_value'] : $default; +} + +function website_set_setting(string $key, string $value, bool $secret = false): bool +{ + $db = website_db(); + if (!$db instanceof mysqli || !website_table_exists(website_table('website_settings'))) { + return false; + } + $table = website_table('website_settings'); + $isSecret = $secret ? 1 : 0; + $stmt = $db->prepare("INSERT INTO `{$table}` (`setting_key`, `setting_value`, `is_secret`, `updated_at`) VALUES (?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE `setting_value` = VALUES(`setting_value`), `is_secret` = VALUES(`is_secret`), `updated_at` = VALUES(`updated_at`)"); + if (!$stmt) { + return false; + } + $stmt->bind_param('ssi', $key, $value, $isSecret); + $ok = $stmt->execute(); + $stmt->close(); + return $ok; +} + +function website_paypal_config(): array +{ + return [ + 'enabled' => website_setting('paypal_enabled', '0') === '1', + 'sandbox' => website_setting('paypal_sandbox', '1') === '1', + 'client_id' => (string)(getenv('GSP_WEBSITE_PAYPAL_CLIENT_ID') ?: website_setting('paypal_client_id', '')), + 'client_secret' => (string)(getenv('GSP_WEBSITE_PAYPAL_CLIENT_SECRET') ?: website_setting('paypal_client_secret', '')), + 'webhook_id' => (string)(getenv('GSP_WEBSITE_PAYPAL_WEBHOOK_ID') ?: website_setting('paypal_webhook_id', '')), + 'currency' => (string)website_setting('paypal_currency', 'USD'), + 'description_prefix' => (string)website_setting('paypal_description_prefix', 'Gameservers.World order'), + ]; +} + +function website_paypal_api_base(array $config): string +{ + return $config['sandbox'] ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com'; +} + +function website_paypal_oauth(array $config): ?string +{ + if ($config['client_id'] === '' || $config['client_secret'] === '') { + return null; + } + $ch = curl_init(website_paypal_api_base($config) . '/v1/oauth2/token'); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => 'grant_type=client_credentials', + CURLOPT_HTTPHEADER => ['Accept: application/json'], + CURLOPT_USERPWD => $config['client_id'] . ':' . $config['client_secret'], + CURLOPT_TIMEOUT => 20, + ]); + $response = curl_exec($ch); + $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($http !== 200 || !is_string($response)) { + return null; + } + $json = json_decode($response, true); + return is_array($json) ? (string)($json['access_token'] ?? '') : null; +} + +function website_services_have_columns(array $columns): bool +{ + $table = website_table('billing_services'); + if (!website_table_exists($table)) { + return false; + } + $existing = website_table_columns($table); + foreach ($columns as $column) { + if (!isset($existing[$column])) { + return false; + } + } + return true; +} + +function website_fetch_remote_servers(): array +{ + $db = website_db(); + $table = website_table('remote_servers'); + if (!$db instanceof mysqli || !website_table_exists($table)) { + return []; + } + $rows = []; + $result = @$db->query("SELECT `remote_server_id`, `remote_server_name`, `agent_ip`, `enabled` FROM `{$table}` ORDER BY `remote_server_name` ASC"); + if ($result instanceof mysqli_result) { + while ($row = $result->fetch_assoc()) { + $rows[] = $row; + } + $result->free(); + } + return $rows; +} + +function website_fetch_invoices_for_user(int $userId): array +{ + $db = website_db(); + $table = website_table('billing_invoices'); + if (!$db instanceof mysqli || !website_table_exists($table)) { + return []; + } + $stmt = $db->prepare("SELECT * FROM `{$table}` WHERE `user_id` = ? ORDER BY `invoice_id` DESC"); + if (!$stmt) { + return []; + } + $stmt->bind_param('i', $userId); + $stmt->execute(); + $result = $stmt->get_result(); + $rows = []; + while ($result instanceof mysqli_result && ($row = $result->fetch_assoc())) { + $rows[] = $row; + } + $stmt->close(); + return $rows; +} + +function website_fetch_orders_for_user(int $userId): array +{ + $db = website_db(); + $table = website_table('billing_orders'); + if (!$db instanceof mysqli || !website_table_exists($table)) { + return []; + } + $stmt = $db->prepare("SELECT * FROM `{$table}` WHERE `user_id` = ? ORDER BY `order_id` DESC"); + if (!$stmt) { + return []; + } + $stmt->bind_param('i', $userId); + $stmt->execute(); + $result = $stmt->get_result(); + $rows = []; + while ($result instanceof mysqli_result && ($row = $result->fetch_assoc())) { + $rows[] = $row; + } + $stmt->close(); + return $rows; +} + +function website_create_invoice_from_cart(int $userId): ?int +{ + $db = website_db(); + if (!$db instanceof mysqli || !website_table_exists(website_table('billing_invoices')) || !website_table_exists(website_table('billing_orders'))) { + return null; + } + + $items = website_cart_items(); + if (empty($items)) { + return null; + } + + $validItems = []; + $total = 0.0; + foreach ($items as $item) { + $service = website_fetch_service_by_id((int)($item['service_id'] ?? 0)); + if (!$service) { + continue; + } + $locations = website_service_locations($service); + $locationId = (string)($item['location_id'] ?? ''); + $slots = (int)($item['slots'] ?? 0); + $min = website_service_min_slots($service); + $max = website_service_max_slots($service); + if ($slots < $min || ($max > 0 && $slots > $max) || !isset($locations[$locationId])) { + continue; + } + $price = (float)($service['price_monthly'] ?? 0); + $durationMonths = max(1, (int)($item['duration_months'] ?? 1)); + $line = [ + 'service_id' => (int)$service['service_id'], + 'service_name' => website_service_name($service), + 'home_name' => trim((string)($item['server_name'] ?? $item['service_name'] ?? website_service_name($service))), + 'remote_server_id' => (int)$locationId, + 'slots' => $slots, + 'duration_months' => $durationMonths, + 'price' => $price * $durationMonths, + 'price_monthly' => $price, + ]; + $validItems[] = $line; + $total += (float)$line['price']; + } + if (empty($validItems)) { + return null; + } + + $invoiceTable = website_table('billing_invoices'); + $orderTable = website_table('billing_orders'); + $currency = website_paypal_config()['currency'] ?: 'USD'; + $metadata = json_encode(['items' => $validItems], JSON_UNESCAPED_SLASHES); + $db->begin_transaction(); + try { + $description = 'Gameservers.World server order'; + $stmt = $db->prepare("INSERT INTO `{$invoiceTable}` (`user_id`, `status`, `amount`, `currency`, `description`, `invoice_date`, `due_date`, `metadata_json`) VALUES (?, 'due', ?, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 3 DAY), ?)"); + if (!$stmt) { + throw new RuntimeException('invoice prepare failed'); + } + $stmt->bind_param('idsss', $userId, $total, $currency, $description, $metadata); + $stmt->execute(); + $invoiceId = (int)$db->insert_id; + $stmt->close(); + + foreach ($validItems as $line) { + $status = 'pending_payment'; + $duration = (string)$line['duration_months']; + $stmt = $db->prepare("INSERT INTO `{$orderTable}` (`invoice_id`, `user_id`, `service_id`, `home_name`, `remote_server_id`, `max_players`, `qty`, `invoice_duration`, `price`, `status`, `order_date`, `metadata_json`) VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, NOW(), ?)"); + if (!$stmt) { + throw new RuntimeException('order prepare failed'); + } + $lineMeta = json_encode($line, JSON_UNESCAPED_SLASHES); + $stmt->bind_param('iiisiisdss', $invoiceId, $userId, $line['service_id'], $line['home_name'], $line['remote_server_id'], $line['slots'], $duration, $line['price'], $status, $lineMeta); + $stmt->execute(); + $stmt->close(); + } + + $db->commit(); + $_SESSION['website_cart'] = []; + website_log_activity('Website invoice created from cart #' . $invoiceId, $userId, 'invoice_created'); + return $invoiceId; + } catch (Throwable $e) { + $db->rollback(); + website_log('Invoice creation failed: ' . $e->getMessage()); + return null; + } +} + +function website_mark_invoice_paid(int $invoiceId, string $provider, string $providerOrderId, string $captureId, string $payerEmail, array $metadata = []): bool +{ + $db = website_db(); + if (!$db instanceof mysqli) { + return false; + } + $invoiceTable = website_table('billing_invoices'); + $orderTable = website_table('billing_orders'); + $paymentTable = website_table('billing_payments'); + if (!website_table_exists($invoiceTable) || !website_table_exists($orderTable) || !website_table_exists($paymentTable)) { + return false; + } + + $db->begin_transaction(); + try { + $stmt = $db->prepare("SELECT `user_id`, `amount`, `currency`, `status` FROM `{$invoiceTable}` WHERE `invoice_id` = ? FOR UPDATE"); + $stmt->bind_param('i', $invoiceId); + $stmt->execute(); + $row = $stmt->get_result()->fetch_assoc(); + $stmt->close(); + if (!is_array($row) || (string)$row['status'] === 'paid') { + $db->commit(); + return true; + } + + $userId = (int)$row['user_id']; + $amount = (float)$row['amount']; + $currency = (string)$row['currency']; + $meta = json_encode($metadata, JSON_UNESCAPED_SLASHES); + + $stmt = $db->prepare("UPDATE `{$invoiceTable}` SET `status` = 'paid', `paid_date` = NOW(), `payment_method` = ?, `payment_txid` = ?, `paypal_order_id` = ?, `paypal_capture_id` = ?, `payer_email` = ? WHERE `invoice_id` = ?"); + $stmt->bind_param('sssssi', $provider, $captureId, $providerOrderId, $captureId, $payerEmail, $invoiceId); + $stmt->execute(); + $stmt->close(); + + $paid = 'paid'; + $provisioning = 'paid'; + $stmt = $db->prepare("UPDATE `{$orderTable}` SET `status` = ?, `payment_txid` = ?, `paid_ts` = NOW() WHERE `invoice_id` = ? AND `status` IN ('pending_payment', 'paid')"); + $stmt->bind_param('ssi', $provisioning, $captureId, $invoiceId); + $stmt->execute(); + $stmt->close(); + + $stmt = $db->prepare("INSERT IGNORE INTO `{$paymentTable}` (`invoice_id`, `user_id`, `provider`, `provider_order_id`, `provider_capture_id`, `amount`, `currency`, `status`, `payer_email`, `created_at`, `metadata_json`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?)"); + $stmt->bind_param('iisssdssss', $invoiceId, $userId, $provider, $providerOrderId, $captureId, $amount, $currency, $paid, $payerEmail, $meta); + $stmt->execute(); + $stmt->close(); + + $db->commit(); + website_log_activity('Website invoice paid #' . $invoiceId, $userId, 'invoice_paid'); + return true; + } catch (Throwable $e) { + $db->rollback(); + website_log('Payment mark-paid failed: ' . $e->getMessage()); + return false; + } +} diff --git a/Panel/modules/website/includes/bootstrap.php b/Panel/modules/website/includes/bootstrap.php index 35a3d1e8..c6aaf41f 100644 --- a/Panel/modules/website/includes/bootstrap.php +++ b/Panel/modules/website/includes/bootstrap.php @@ -32,6 +32,10 @@ foreach ($websiteConfigFiles as $configFile) { } } +if (is_readable(__DIR__ . '/billing.php')) { + require_once __DIR__ . '/billing.php'; +} + $websiteDefaults = [ 'site_name' => 'Gameservers.World', 'site_tagline' => 'Developer-backed game hosting for modern and legacy communities, with full server access, daily backups, and optional custom engineering help through Runlevel Systems.', @@ -311,7 +315,7 @@ function website_database_settings(): ?array $merged = array_replace($merged, website_read_php_assignments($billingConfig, $keys)); } - foreach (['db_host', 'db_user', 'db_name', 'table_prefix'] as $requiredKey) { + foreach (['db_host', 'db_user', 'db_name'] as $requiredKey) { if (empty($merged[$requiredKey])) { $settings = null; return $settings; @@ -418,7 +422,7 @@ function website_panel_user_by_id(int $userId): ?array { $db = website_db(); $prefix = website_table_prefix(); - if (!$db instanceof mysqli || $prefix === '' || $userId <= 0) { + if (!$db instanceof mysqli || $userId <= 0) { return null; } @@ -439,7 +443,7 @@ function website_panel_user_by_login(string $login): ?array { $db = website_db(); $prefix = website_table_prefix(); - if (!$db instanceof mysqli || $prefix === '' || $login === '') { + if (!$db instanceof mysqli || $login === '') { return null; } @@ -532,7 +536,7 @@ function website_log_activity(string $message, int $userId = 0, string $eventTyp { $db = website_db(); $prefix = website_table_prefix(); - if (!$db instanceof mysqli || $prefix === '') { + if (!$db instanceof mysqli) { return; } @@ -602,14 +606,18 @@ function website_checkout_url(): string function website_register_url(string $returnPath = 'cart.php'): string { - return panel_url('index.php?m=register'); + $path = 'register.php'; + if ($returnPath !== '') { + $path .= '?return=' . rawurlencode(website_safe_return_path($returnPath, 'cart.php')); + } + return website_url($path); } function website_fetch_service_by_id(int $serviceId): ?array { $db = website_db(); $prefix = website_table_prefix(); - if (!$db instanceof mysqli || $prefix === '' || $serviceId <= 0) { + if (!$db instanceof mysqli || $serviceId <= 0) { return null; } @@ -658,7 +666,7 @@ function website_service_name(array $service): string function website_service_min_slots(array $service): int { - foreach (['min_slots', 'minimum_slots', 'slots_min'] as $column) { + foreach (['slot_min_qty', 'min_slots', 'minimum_slots', 'slots_min'] as $column) { if (isset($service[$column]) && (int)$service[$column] > 0) { return (int)$service[$column]; } @@ -670,7 +678,7 @@ function website_service_min_slots(array $service): int function website_service_max_slots(array $service): int { - foreach (['max_slots', 'maximum_slots', 'slots_max', 'max_players'] as $column) { + foreach (['slot_max_qty', 'max_slots', 'maximum_slots', 'slots_max', 'max_players'] as $column) { if (isset($service[$column]) && (int)$service[$column] > 0) { return (int)$service[$column]; } @@ -687,7 +695,7 @@ function website_service_locations(array $service): array } $locations = []; - foreach (preg_split('/\s*,\s*/', $raw) ?: [] as $remoteServerId) { + foreach (preg_split('/[\s,]+/', $raw) ?: [] as $remoteServerId) { $remoteServerId = trim($remoteServerId); if ($remoteServerId === '' || !ctype_digit($remoteServerId)) { continue; @@ -732,7 +740,7 @@ function website_cart_total(): float { $total = 0.0; foreach (website_cart_items() as $item) { - $total += (float)($item['monthly_total'] ?? 0); + $total += (float)($item['line_total'] ?? $item['monthly_total'] ?? 0); } return $total; } @@ -805,7 +813,7 @@ function website_service_image_url(string $imageValue): string return website_asset('images/games/' . $fileName); } -function website_fetch_services(int $limit = 0): array +function website_fetch_services(int $limit = 0, bool $includeDisabled = false): array { $db = website_db(); if (!$db instanceof mysqli) { @@ -813,24 +821,16 @@ function website_fetch_services(int $limit = 0): array } $prefix = website_table_prefix(); - if ($prefix === '') { - return []; - } - $sql = "SELECT bs.service_id, - bs.service_name, - bs.description, - bs.img_url, - bs.price_monthly, - bs.remote_server_id, + $sql = "SELECT bs.*, ch.game_name AS cfg_game_name, ch.game_key AS cfg_game_key, ch.home_cfg_file AS cfg_file FROM `{$prefix}billing_services` bs LEFT JOIN `{$prefix}config_homes` ch ON ch.home_cfg_id = bs.home_cfg_id - WHERE bs.enabled = 1 + WHERE " . ($includeDisabled ? '1 = 1' : "bs.enabled = 1 AND bs.remote_server_id <> '' - AND bs.remote_server_id IS NOT NULL + AND bs.remote_server_id IS NOT NULL") . " ORDER BY bs.service_name ASC"; if ($limit > 0) { diff --git a/Panel/modules/website/includes/footer.php b/Panel/modules/website/includes/footer.php index 55b40216..981d30b3 100644 --- a/Panel/modules/website/includes/footer.php +++ b/Panel/modules/website/includes/footer.php @@ -38,9 +38,11 @@ $currentUser = website_current_user();