Commit Graph

24 Commits

Author SHA1 Message Date
myron 8d27290831 Fix 6 code review findings: auth, mysqldump stderr, dead code, audit logs
- backup.php: replace manual admin check with requireAdmin(); suppress
  mysqldump password warning (2>&1 → 2>/dev/null) to prevent corrupt dumps
- ttg-backup.sh: same mysqldump stderr fix
- admin.php toggle_user: fix undefined $adminId/$userId in logAdminAction
  call — use $_SESSION['user_id'] and $uid instead
- admin.php chat_clear_all: wrap in try/catch and add logAdminAction audit
- admin.php: delete unreachable broadcast query block after break statement
- admin/index.php: fix cashouts_total formatted as currency — use parseInt
  (tokens are whole numbers, not dollars)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 10:02:07 +00:00
myron 9470b021b6 Fix bogus $sent check on 20 non-email actions in admin.php
Every case that wasn't actually sending email had copy-pasted the
email-send result check, causing all those actions (delete_pending,
payment_settings_update, etc.) to always return 'Failed to send reset
email' even on success.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 09:04:16 +00:00
myron f5a72c55f5 Add automated backup system
- api/backup.php: list/create/download/delete backups; streams zip directly
  for downloads; 7-backup rolling prune on each create
- Each backup is a single zip containing all of public_html + a full
  mysqldump of tomt_ttg_db
- Cron at 2 AM daily via /usr/local/bin/ttg-backup.sh (already installed)
- Admin UI: 💾 Backups nav item under System section; shows backup list
  with date/size, Download + Delete per row; Create Backup Now button
  with live status; auto-loads when section is opened

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 22:14:32 +00:00
myron c9cf26edca Show dollar/token totals on platform cards instead of counts
Purchases shows sum of amount_cents as dollars, cashouts shows sum
of tokens with coin icon.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 22:08:31 +00:00
myron 253cd0a743 Fix platform_stats returning Forbidden — $isAdmin undefined in admin.php
requireAdmin() already guards the whole file; the extra check was
referencing an undefined variable that always evaluated false.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 22:06:48 +00:00
myron d8202427ae Add platform credit overview to dashboard
New section below pending purchases/cashouts: one square card per
active platform showing net credit balance, completed purchase count,
and sent cashout count. Loads on page load alongside other dashboard
data. Credits turn yellow below 100 and red at/below 0 with a warning.
Clicking a card jumps to Game Management and opens that platform's
credit modal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 22:03:38 +00:00
myron f54cdb11db Auto-debit platform credits when purchase is approved
When a pending purchase is resolved as completed:
- Inserts a debit row into platform_credits for the matching platform
  (joins token_purchases.platform_id slug → platforms.id)
- Debit notes include purchase #, player name, username, token count, amount, method
- Total shown in credit modal now subtracts debits from credits (net balance)

Credit history table updates:
- CREDIT/DEBIT type badges, debit rows tinted red with − prefix
- Debit rows show "Purchase #X ↗" button that closes modal, jumps to
  the Purchases section (all tab), and highlights that purchase row
- Edit/delete buttons hidden on auto-generated debit rows

Also fixes: resolve_purchase was echoing $sent (undefined variable bug)
Also fixes: purchaseCard div now has id="pr-N" so jump-highlight works

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 21:38:03 +00:00
myron 1367fa334b Fix credit accounting popup sending to wrong API endpoint
saveCreditEntry and deleteCreditEntry were using apiFetch() which routes
to /api/admin.php, but credits_create/update/delete only exist in
/api/platforms.php — causing the Unknown action error on every save.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 21:27:53 +00:00
myron b6adb7a3f0 Blur credentials for non-master admins in game management
- Game list cards: login/password fields blurred with user-select/pointer-events
  disabled for non-master admins; URLs and guide remain readable
- View-only edit panel: credential fields blurred, copy button hidden for creds;
  URL fields retain open + copy buttons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:58:12 +00:00
myron 90b497dae5 Increase admin font sizes by 1px for readability
- CSS vars: xs 11→12, sm 13→14, base 15→16, md 16→17, lg 18→19, xl 20→21, 2xl 24→25
- Body font-size: 16→17px
- Input/control CSS classes: 16→17px

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:56:12 +00:00
myron 56ea742495 Fix add new game: reset form on section load, add prominent Add New Game button
- resetGameForm() now called every time Game Management section is opened,
  preventing stuck edit state (disabled slug, wrong form title)
- Added prominent Add New Game button at top of section (master admin only)
- DOMContentLoaded init ensures form state is correct on page load

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:49:57 +00:00
myron 0c96b0ad7c Game Management: soft-delete, slug reuse, new game form fix, master-admin gating
- DB: added is_deleted, deleted_at columns to platforms table
- Soft delete: archive button moves games to archived section instead of hard delete
- Archived section: master admin can restore (reactivates) or permanently delete
- Slug reuse: creating a game with an archived slug reactivates the old record
- New game form: master admin always sees add form + agent info; other admins hidden
- Edit: non-master admins have form card revealed on edit
- Delete/Add buttons: only visible to master admin
- api/platforms.php: public and admin_list queries exclude archived games
- api/admin.php: platforms_archived, platforms_restore, platforms_purge actions added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:45:31 +00:00
myron 185c27f6b4 Fix game management save/retrieve; add last-edited to game cards
Root cause: saves went through admin.php which still used old console_url column
and had broken response using undefined $sent variable (always returned error).

- api/admin.php: platforms_create/update/delete fully rewritten with all agent
  fields, master-admin gating, and correct json_encode responses
- api/admin.php: update now sets updated_at=NOW() on save
- admin/index.php: game cards show last-edited date (✏️ from updated_at)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:15:55 +00:00
myron 7eade583f7 Restrict Agent Info and Credit Accounting to master admin only; protect master admin account
- Agent Info: master admin sees full edit form; other admins see view-only panel with Copy and Open URL buttons
- Credit Accounting: master admin can manage entries; other admins see total only (Manage Credits button hidden)
- API: credits_create/update/delete require master admin; platform update strips agent fields for non-master
- Players: suspend/delete buttons disabled when viewing master admin account (UI + JS guards)
- URL fields (Agent Link, Games Link): open-in-new-tab arrow button added in both edit and view modes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:06:17 +00:00
myron f50d1d481d Add Credit Accounting section to game management
- New table: platform_credits (id, platform_id, credits_purchased, credit_date, payment_method, notes)
- API: credits_list, credits_create, credits_update, credits_delete actions (admin-only)
- Admin form: Credit Accounting box showing Available Credits total; Manage Credits button opens modal
- Modal: Total Credits header, add/edit/delete entries with credits, date, payment method, notes
- Game list cards: show live credit total per game (cyan, loads async)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:00:15 +00:00
myron 99079340cb Add sub-account and cashier credential fields to game management
- DB: added sub_agent_login, sub_agent_password, cashier_login, cashier_password to platforms table
- API: create/update handle all 4 new fields
- Admin: Sub-Account and Cashier sections added inside Agent Info box; game list cards display all new fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:51:37 +00:00
myron 0aec13daf4 Add agent fields to game management
- DB: renamed console_url to agent_link, added agent_login, agent_password, games_link, agent_guide to platforms table
- api/platforms.php: create/update now handles all 5 agent fields (admin-only)
- admin/index.php: game form has new Agent Info section (purple, admin-only styling); game list cards show all agent fields inline; JS saveGame/editGame/resetGameForm updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:39:48 +00:00
myron 497071e1b7 Fix pending_signups stat pollution and use branded reset email
- pending_signups stat and list queries now filter username != __reset__
  so active password-reset rows no longer inflate the signup counter or
  appear in the admin pending-signups list
- send_password_reset now calls sendPasswordResetEmail() from mailer.php
  instead of building a plain-text cybermailSend() call inline; the
  wrapper sends a branded dark-theme HTML email matching the verification
  email style
2026-06-03 06:01:49 +00:00
myron 5b364db2a5 Surface cybermailSend failure to admin on password reset
Previously the endpoint always returned success:true regardless of
whether the email was actually delivered. Now captures the bool return
value and returns success:false with an error message if CyberMail
fails, so the admin knows to retry rather than assuming delivery.
2026-06-03 03:57:22 +00:00
myron 9815db29d0 Add reset_password.php — password reset redemption page
Handles the /reset_password.php?token=... URL generated by the
admin send_password_reset action. Flow:
- GET: validates token against pending_registrations (username=__reset__,
  not expired), shows set-new-password form
- POST: re-validates token, enforces 6-char min + confirm match,
  bcrypt-hashes the new password, updates users.password by email,
  deletes the pending row to prevent reuse
- Invalid/expired token shows a clear error with link back to home

Matches the dark gaming aesthetic of verify.php.
2026-06-03 03:56:17 +00:00
myron 18ec3a7143 Fix broken password reset INSERT — SQL syntax error and wrong token value
The INSERT had two compounding bugs:
1. ".?" in the VALUES clause — a PHP dot inside a double-quoted string
   is a literal character, not concatenation. MySQL saw it as a syntax
   error and the INSERT always failed silently (no try/catch).
2. The token column had the literal string __reset__ hardcoded instead
   of a ? placeholder, so even if the INSERT had run, the real random
   token would never have been stored — the reset link always invalid.

Fix: VALUES ("__reset__","",?,?,?,?) with execute(alias,email,token,exp)
giving 4 placeholders for 4 params, all columns correctly bound.
2026-06-03 03:54:16 +00:00
myron ad57071f97 Add DB schema (22 tables) and vhost config 2026-05-25 13:52:18 +00:00
myron 894392065c Security: remove test/debug/install files from production 2026-05-22 13:05:18 +00:00
myron 2e587941c2 Initial commit 2026-05-22 12:52:50 +00:00