21 Commits

Author SHA1 Message Date
myron 483026fd07 Pass saved alias to platform on launch; copy to clipboard
- platforms table gets url_alias_param column (configurable per platform)
- Admin game form has new "Username URL Param" field — leave blank if platform
  doesn't support it, or set to e.g. "username" if it does
- Platform cards now use onclick openPlatform() instead of plain href:
  copies player's saved alias to clipboard on every click, and if
  url_alias_param is set appends ?param=alias to the launch URL
- Toast notification confirms "Alias copied — paste into login"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 11:13:45 +00:00
myron 44a98eba15 Shade disabled payout methods when admin turns them off
- payout_methods list now includes admin_enabled flag via JOIN on admin_payout_settings
- Disabled methods appear at 45% opacity with UNAVAILABLE/DISABLED BY ADMIN badge
  in both the cashout radio list and profile payout tab; radio is disabled so they
  can't be selected, but the delete button remains
- Set Default button hidden on disabled methods
- cashout.php server-side guard rejects submissions using a disabled method type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 11:04:18 +00:00
myron 428bc86eb7 Filter player payout types by admin-enabled methods
cashout_method_types list now JOINs admin_payout_settings so the
player's profile payout dropdown only shows types the admin can
actually process.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 10:58:12 +00:00
myron 8238db3026 Add URL-based referral share verification with auto-scraper
Players now paste the URL of their post instead of just clicking a
platform button. The server fetches the URL and looks for the player's
referral code in the page content. If found, the share is auto-approved
and tokens are awarded immediately. If not (login wall, private page,
code missing), it falls into the pending queue with a reason so admins
can click the link directly for manual review.

- api/referrals.php: replace submit_share with URL-accepting version;
  add scrapeForReferralCode() (SSRF-guarded cURL, 8s timeout, 512KB cap)
  and inferPlatformFromUrl() helpers
- db/schema.sql: add share_url, auto_verified, verify_result columns
- index.php: replace platform buttons with URL input form; show auto-
  verify result inline; shares list shows URL and auto-verify badge
- admin/index.php: share cards show clickable URL, auto-check result
  label, and auto-verified tag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 10:16:45 +00:00
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 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 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 2e587941c2 Initial commit 2026-05-22 12:52:50 +00:00