Site Builder
Editing:
tools-admin.php
writable 0666
<?php /***************************************************************** * AI‑Tools · Global tool manager (business / profile branches) * ------------------------------------------------------------- * Location: /ai‑tools/tools‑admin.php * Branches: /ai‑tools/business‑tools * /ai‑tools/profile‑tools * Each branch holds one JSON <branch>.json *****************************************************************/ require_once __DIR__.'/../members/lib/auth.php'; require_login(); if (current_user()['role'] !== 'admin') forbidden_page(); /* ---------- configuration ------------------------------------ */ const ROOT_DIR = __DIR__; // /public_html/ai‑tools const BRANCHES = ['business-tools','profile-tools']; const VALID_TIERS = ['free','premium','admin']; /* ---------- helper: load / save JSON ------------------------- */ function json_path(string $branch): string { return ROOT_DIR . "/$branch/$branch.json"; } function load_json(string $branch): array { $f = json_path($branch); if (!is_file($f)) return []; return json_decode(file_get_contents($f), true) ?: []; } function save_json(string $branch, array $arr): void { $f = json_path($branch); file_put_contents($f, json_encode($arr, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOCK_EX ); } /* ---------- pick branch (default = first) -------------------- */ $branch = $_POST['branch'] ?? $_GET['branch'] ?? BRANCHES[0]; if (!in_array($branch, BRANCHES, true)) $branch = BRANCHES[0]; /* ---------- current list + FS scan --------------------------- */ $tools = []; // indexed by folder name foreach (load_json($branch) as $row) $tools[$row['name']] = $row; /* Scan a branch directory and return merged list */ function scan_fs(string $branch, array $prev): array { $found = []; foreach (glob(ROOT_DIR."/$branch/*", GLOB_ONLYDIR) as $dir) { $name = basename($dir); $php = "tools-$name.php"; if (!is_file("$dir/$php")) continue; // skip if no driver $rel = "$name/$php"; $old = $prev[$name] ?? []; $found[$name] = [ 'name' => $name, 'file' => $php, 'relative_path' => $rel, 'http_path' => "/ai-tools/$branch/$rel", 'active' => $old['active'] ?? false, 'tier' => in_array($old['tier'] ?? '', VALID_TIERS, true) ? $old['tier'] : 'free' ]; } /* preserve order of previous list, append new ones */ $ordered = []; foreach (array_column($prev,'name') as $n) if (isset($found[$n])) $ordered[$n] = $found[$n]; foreach ($found as $n=>$row) if (!isset($ordered[$n])) $ordered[$n] = $row; return $ordered; } /* ---------- POST actions ------------------------------------- */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { /* (re)scan branch ------------------------------------------------ */ if ($_POST['action'] === 'scan') { $tools = scan_fs($branch, $tools); save_json($branch, array_values($tools)); header("Location: tools-admin.php?branch=$branch&msg=scanned"); exit; } /* save changes --------------------------------------------------- */ if ($_POST['action'] === 'save') { /* re‑order */ if (isset($_POST['order'])) { $order = explode(',', $_POST['order']); $ordered = []; foreach ($order as $n) if (isset($tools[$n])) $ordered[$n]=$tools[$n]; foreach ($tools as $n=>$row) if (!isset($ordered[$n])) $ordered[$n]=$row; $tools = $ordered; } /* active + tier */ foreach ($tools as $n => &$row) { $row['active'] = isset($_POST['act'][$n]); $row['tier'] = in_array($_POST['tier'][$n] ?? 'free', VALID_TIERS, true) ? $_POST['tier'][$n] : 'free'; } save_json($branch, array_values($tools)); header("Location: tools-admin.php?branch=$branch&msg=saved"); exit; } } /* ---------- ensure JSON exists (fresh install) --------------- */ if (!is_file(json_path($branch))) { // first visit → ask admin to scan if (!isset($_GET['first'])) { header("Location: tools-admin.php?branch=$branch&first=1"); exit; } } $tools = scan_fs($branch, $tools); // silent fs sync on every GET save_json($branch, array_values($tools)); /* ---------------------------------- HTML --------------------- */ ?> <!doctype html> <title>AI Tool Manager – BestDealOn</title> <meta name=viewport content="width=device-width,initial-scale=1"> <style> :root{--brand:#0066ff;--bg:#f6f9ff;--fg:#111;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif} body{margin:0;background:var(--bg);color:var(--fg)} main{max-width:880px;margin:2.5rem auto;padding:0 1rem} h1{font-size:1.7rem;margin-top:0} select,input{padding:.5rem .7rem;border:1px solid #ccd2e2;border-radius:6px;font:inherit} table{width:100%;border-collapse:collapse;margin-top:1.4rem;font-size:.92rem} th,td{padding:.55rem .7rem;border-bottom:1px solid #e2e8f3} th{background:#edf3ff;font-weight:600;text-align:left} .drag{cursor:grab;color:#888;text-align:center;width:26px} .center{text-align:center} button{padding:.55rem 1.3rem;border:none;border-radius:6px;font-weight:600;cursor:pointer;margin-right:.6rem} .save{background:var(--brand);color:#fff} .scan{background:#ffb31c;color:#fff} .msg{padding:.8rem 1rem;border-radius:8px;margin-top:.9rem;font-weight:600} .ok{background:#e7f9eb;color:#0b8133} tr.dragging{opacity:.5} @media(prefers-color-scheme:dark){ :root{--bg:#0d1117;--fg:#e6edf3;--brand:#2f81f7} table,th,td{border-color:#30363d} th{background:#1d2b55} select{background:#0d1117;color:var(--fg);border-color:#444c5e} } </style> <main> <h1>AI Tool Manager</h1> <form id="branchForm" method="get" style="margin-bottom:1rem"> <label for="bSel"><strong>Branch :</strong></label> <select id="bSel" name="branch" onchange="this.form.submit()"> <?php foreach (BRANCHES as $b): ?> <option value="<?= $b ?>" <?= $b===$branch?'selected':'' ?>> <?= ucfirst(str_replace('-',' ',$b)) ?> </option> <?php endforeach ?> </select> </form> <?php if(isset($_GET['msg'])): ?> <div class="msg ok"> <?= $_GET['msg']==='saved' ?'Changes saved ✓' :'Scan complete – new tools added as inactive ✓' ?> </div> <?php endif; ?> <?php if(!$tools): /* fresh install – no JSON yet */ ?> <form method="post"> <input type="hidden" name="branch" value="<?= htmlspecialchars($branch) ?>"> <input type="hidden" name="action" value="scan"> <p>No tool list found for this branch.</p> <button class="scan">🔍 Scan for tools</button> </form> <?php else: /* normal table */ ?> <form id="frm" method="post"> <input type="hidden" name="branch" value="<?= htmlspecialchars($branch) ?>"> <input type="hidden" name="order" id="orderField"> <input type="hidden" name="action" value="save"> <table id="toolTable"> <tr> <th class="drag">≡</th><th>Name</th><th>PHP file</th> <th class="center">Active?</th><th class="center">Tier</th> </tr> <?php foreach ($tools as $row): $n=htmlspecialchars($row['name']); ?> <tr data-name="<?= $n ?>"> <td class="drag">≡</td> <td><?= $n ?></td> <td><code><?= htmlspecialchars($row['relative_path']) ?></code></td> <td class="center"> <input type="checkbox" name="act[<?= $n ?>]" <?= $row['active']?'checked':'' ?>> </td> <td class="center"> <select name="tier[<?= $n ?>]"> <?php foreach (VALID_TIERS as $t): ?> <option value="<?= $t ?>" <?= $row['tier']===$t?'selected':'' ?>><?= $t ?></option> <?php endforeach ?> </select> </td> </tr> <?php endforeach; ?> </table> <p style="margin-top:1.4rem"> <button class="save">💾 Save changes</button> <button class="scan" name="action" value="scan">🔍 Scan for new tools</button> </p> </form> <?php endif; ?> <p style="margin-top:2rem"><a href="/openai/models.php">← Model Manager</a></p> <p style="margin-top:2rem"><a href="/members/dashboard.php">← Back to dashboard</a></p> </main> <script> /* --- drag & drop reorder (same pattern as modules) ----------- */ const table = document.getElementById('toolTable'); let dragging; table.addEventListener('pointerdown', e => { const h = e.target.closest('.drag'); if (!h) return; dragging = h.parentElement; dragging.classList.add('dragging'); e.preventDefault(); }); table.addEventListener('pointermove', e => { if (!dragging) return; const rows = [...table.querySelectorAll('tr[data-name]:not(.dragging)')]; const after = rows.find(r => e.clientY < r.getBoundingClientRect().top + r.offsetHeight / 2); table.tBodies[0].insertBefore(dragging, after || null); }); table.addEventListener('pointerup', () => { if (dragging){ dragging.classList.remove('dragging'); dragging = null; } }); /* write order on submit */ const frm = document.getElementById('frm'); if (frm) frm.addEventListener('submit', () => { const names = [...table.querySelectorAll('tr[data-name]')].map(r => r.dataset.name); document.getElementById('orderField').value = names.join(','); }); </script>
Save changes
Create folder
writable 0777
Create
Cancel