214 lines
16 KiB
PHP
214 lines
16 KiB
PHP
<?php
|
|
require_once('/opt/wevads/config/credentials.php');
|
|
header('Content-Type: text/html; charset=UTF-8');
|
|
$pdo = get_pdo('adx_system');
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS admin.quick_access_config (
|
|
id SERIAL PRIMARY KEY, section VARCHAR(50) NOT NULL, label VARCHAR(100) NOT NULL,
|
|
url TEXT NOT NULL, icon VARCHAR(50) DEFAULT 'fa-link', sort_order INTEGER DEFAULT 0,
|
|
is_active BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT NOW()
|
|
)");
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
header('Content-Type: application/json');
|
|
$action = $_POST['action'] ?? '';
|
|
|
|
if ($action === 'add') {
|
|
$stmt = $pdo->prepare("INSERT INTO admin.quick_access_config (section,label,url,icon,sort_order) VALUES (?,?,?,?,?)");
|
|
$stmt->execute([$_POST['section'],$_POST['label'],$_POST['url'],$_POST['icon']??'fa-link',(int)($_POST['sort_order']??0)]);
|
|
echo json_encode(['success'=>true,'id'=>$pdo->lastInsertId()]); exit;
|
|
}
|
|
if ($action === 'delete') {
|
|
$pdo->prepare("DELETE FROM admin.quick_access_config WHERE id=?")->execute([$_POST['id']]);
|
|
echo json_encode(['success'=>true]); exit;
|
|
}
|
|
if ($action === 'toggle') {
|
|
$pdo->prepare("UPDATE admin.quick_access_config SET is_active=NOT is_active WHERE id=?")->execute([$_POST['id']]);
|
|
echo json_encode(['success'=>true]); exit;
|
|
}
|
|
if ($action === 'seed_defaults') {
|
|
$count = $pdo->query("SELECT COUNT(*) FROM admin.quick_access_config")->fetchColumn();
|
|
if ($count == 0) {
|
|
$defaults = [
|
|
['footer','Semi-Auto Send','semi-auto-send.php','fa-paper-plane',1],
|
|
['footer','Brain Engine','brain-orchestrator.php','fa-brain',2],
|
|
['footer','HAMID IA','hamid-fullscreen.php','fa-robot',3],
|
|
['footer','Scraping','scraping-factory.php','fa-spider',4],
|
|
['header_quick','Extract Values','tools/extractor.html','fa-wrench',1],
|
|
['header_quick','Add Multiple MTA','mta-servers/multi-add.html','fa-plus-circle',2],
|
|
['header_quick','MTA Servers List','mta-servers.html','fa-server',3],
|
|
['header_quick','Template Config','pmta/templates.html','fa-file',4],
|
|
['header_quick','Suppression','offers/suppression.html','fa-trash',5],
|
|
['header_quick','Send Page','production/send-process.html','fa-paper-plane',6],
|
|
['header_quick','PMTA Commands','pmta/commands.html','fa-terminal',7],
|
|
['header_quick','VMTAs List','mta-servers/vmtas-list.html','fa-list',8],
|
|
['header_quick','MTA Drops','production/mta-drops.html','fa-tachometer',9],
|
|
['header_quick','MTA Tests','production/mta-tests.html','fa-flask',10],
|
|
['header_quick','n8n Automation','n8n.php','fa-project-diagram',11],
|
|
['header_quick','WEVAL Orchestrator','weval-orchestrator.php','fa-tasks',12],
|
|
['header_cloud','Cloudflare API','dkim_setup.php','fa-shield',1],
|
|
['header_cloud','Microsoft API','cloudapis/microsoft.html','fa-windows',2],
|
|
['header_cloud','Google API','cloudapis/google.html','fa-google',3],
|
|
['header_cloud','AWS S3','s3_upload_direct.php','fa-amazon',4],
|
|
];
|
|
$stmt = $pdo->prepare("INSERT INTO admin.quick_access_config (section,label,url,icon,sort_order) VALUES (?,?,?,?,?)");
|
|
foreach ($defaults as $d) $stmt->execute($d);
|
|
echo json_encode(['success'=>true,'seeded'=>count($defaults)]); exit;
|
|
}
|
|
echo json_encode(['success'=>false,'message'=>'Already has data. Delete all first.']); exit;
|
|
}
|
|
if ($action === 'apply') {
|
|
$rows = $pdo->query("SELECT * FROM admin.quick_access_config WHERE is_active=true ORDER BY section,sort_order")->fetchAll(PDO::FETCH_ASSOC);
|
|
$sections = [];
|
|
foreach ($rows as $r) $sections[$r['section']][] = $r;
|
|
$results = [];
|
|
|
|
// Footer
|
|
if (!empty($sections['footer'])) {
|
|
$links = [];
|
|
foreach ($sections['footer'] as $item) $links[] = '["'.addslashes($item['url']).'","'.addslashes($item['label']).'"]';
|
|
$linksJS = 'var links=['.implode(',',$links).'];';
|
|
$js = file_get_contents('/opt/wevads/public/js/footer-toggles.js');
|
|
$js = preg_replace('/var links=\[.*?\];/', $linksJS, $js);
|
|
file_put_contents('/opt/wevads/public/js/footer-toggles.js', $js);
|
|
$results[] = 'Footer: '.count($sections['footer']).' items';
|
|
}
|
|
|
|
// Cloud dropdown
|
|
if (!empty($sections['header_cloud'])) {
|
|
$master = file_get_contents('/opt/wevads/app/views/master.html');
|
|
$items = '';
|
|
foreach ($sections['header_cloud'] as $item) {
|
|
$items .= '<li><a href="{echo $app[\'base_url\']}/'.htmlspecialchars($item['url']).'"><i class="fa '.htmlspecialchars($item['icon']).'" style="margin-right:8px;"></i> '.htmlspecialchars($item['label']).'</a></li>'."\n";
|
|
}
|
|
$pattern = '/(<!-- BEGIN CLOUD DROPDOWN -->.*?<ul class="dropdown-menu dropdown-menu-default">)(.*?)(\s*<\/ul>\s*<\/li>\s*<!-- END CLOUD DROPDOWN -->)/s';
|
|
$master = preg_replace($pattern, '$1'."\n".$items.'$3', $master);
|
|
file_put_contents('/opt/wevads/app/views/master.html', $master);
|
|
$results[] = 'Cloud: '.count($sections['header_cloud']).' items';
|
|
}
|
|
|
|
// Quick Access dropdown
|
|
if (!empty($sections['header_quick'])) {
|
|
$master = file_get_contents('/opt/wevads/app/views/master.html');
|
|
$items = '';
|
|
foreach ($sections['header_quick'] as $item) {
|
|
$items .= '<li><a href="{echo $app[\'base_url\']}/'.htmlspecialchars($item['url']).'" target="_blank"><i class="fa '.htmlspecialchars($item['icon']).'" style="margin-right:8px;"></i> '.htmlspecialchars($item['label']).'</a></li>'."\n";
|
|
}
|
|
$pattern = '/(<!-- BEGIN QUICK ACCESS DROPDOWN -->.*?<ul class="dropdown-menu dropdown-menu-default">)(.*?)(\s*<\/ul>\s*<\/li>\s*<!-- END QUICK ACCESS DROPDOWN -->)/s';
|
|
$master = preg_replace($pattern, '$1'."\n".$items.'$3', $master);
|
|
file_put_contents('/opt/wevads/app/views/master.html', $master);
|
|
$results[] = 'Quick Access: '.count($sections['header_quick']).' items';
|
|
}
|
|
|
|
echo json_encode(['success'=>true,'results'=>$results]); exit;
|
|
}
|
|
echo json_encode(['error'=>'Unknown action']); exit;
|
|
}
|
|
|
|
$items = $pdo->query("SELECT * FROM admin.quick_access_config ORDER BY section, sort_order")->fetchAll(PDO::FETCH_ASSOC);
|
|
$secs = [];
|
|
foreach ($items as $r) $secs[$r['section']][] = $r;
|
|
$cpu = (float)trim(shell_exec("top -bn1 | grep 'Cpu(s)' | awk '{print 100 - \$8}'") ?? '0');
|
|
$ram = (float)trim(shell_exec("free | awk '/Mem:/{printf(\"%.1f\", \$3/\$2*100)}'") ?? '0');
|
|
$storage = (int)trim(shell_exec("df / | awk 'NR==2{print \$5}' | tr -d '%'") ?? '0');
|
|
function mcolor($v,$t=75,$m=40){return $v>$t?'#ef4444':($v>$m?'#f59e0b':'#10b981');}
|
|
function mclass($v,$t=75,$m=40){return $v>$t?'red':($v>$m?'yellow':'green');}
|
|
?><!DOCTYPE html>
|
|
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
<title>Quick Access & Menus Admin</title>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
|
<style>
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0f172a;color:#e2e8f0;min-height:100vh}
|
|
.hdr{background:linear-gradient(135deg,#0891b2,#06b6d4);padding:18px 30px;display:flex;justify-content:space-between;align-items:center}
|
|
.hdr h1{font-size:20px;color:#fff;display:flex;align-items:center;gap:10px}
|
|
.hdr .back{color:#fff;text-decoration:none;padding:8px 16px;background:rgba(255,255,255,.15);border-radius:6px;font-size:13px}
|
|
.container{max-width:1400px;margin:0 auto;padding:20px}
|
|
.metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:15px;margin-bottom:25px}
|
|
.mc{background:#1e293b;border:1px solid #334155;border-radius:10px;padding:18px;text-align:center}
|
|
.mc .v{font-size:30px;font-weight:700;margin:6px 0}.mc .l{font-size:11px;color:#94a3b8;text-transform:uppercase;letter-spacing:1px}
|
|
.mc .bar{height:6px;background:#334155;border-radius:3px;margin-top:10px;overflow:hidden}
|
|
.mc .bf{height:100%;border-radius:3px;transition:width .5s}
|
|
.green{color:#10b981}.yellow{color:#f59e0b}.red{color:#ef4444}
|
|
.tabs{display:flex;gap:5px;margin-bottom:20px;background:#1e293b;padding:5px;border-radius:10px}
|
|
.tab{padding:10px 20px;border-radius:8px;cursor:pointer;font-size:13px;font-weight:600;color:#94a3b8;border:none;background:0;transition:all .2s}
|
|
.tab.active{background:#0891b2;color:#fff}.tab:hover:not(.active){background:#334155;color:#fff}
|
|
.sp{display:none;background:#1e293b;border:1px solid #334155;border-radius:10px;padding:20px}.sp.active{display:block}
|
|
.sh{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px}
|
|
.sh h3{font-size:16px;color:#06b6d4;display:flex;align-items:center;gap:8px}
|
|
table{width:100%;border-collapse:collapse}th{text-align:left;padding:10px;font-size:11px;color:#64748b;text-transform:uppercase;border-bottom:1px solid #334155}
|
|
td{padding:10px;border-bottom:1px solid rgba(51,65,85,.3);font-size:13px}tr:hover{background:rgba(8,145,178,.05)}
|
|
.ip{width:30px;height:30px;background:#0f172a;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#06b6d4}
|
|
.btn{padding:6px 14px;border:none;border-radius:6px;cursor:pointer;font-size:12px;font-weight:600;transition:all .2s}
|
|
.bc{background:#0891b2;color:#fff}.bc:hover{background:#06b6d4}
|
|
.br{background:#dc2626;color:#fff}.br:hover{background:#ef4444}
|
|
.bg{background:#059669;color:#fff}.bg:hover{background:#10b981}
|
|
.by{background:#d97706;color:#fff}.by:hover{background:#f59e0b}
|
|
.bs{padding:4px 10px;font-size:11px}
|
|
.af{display:none;background:#0f172a;border:1px solid #334155;border-radius:8px;padding:15px;margin-top:15px}.af.vis{display:block}
|
|
.fr{display:grid;grid-template-columns:120px 1fr 1.5fr 80px 80px auto;gap:10px;align-items:center}
|
|
.fr input,.fr select{background:#1e293b;border:1px solid #334155;color:#e2e8f0;padding:8px 12px;border-radius:6px;font-size:13px}
|
|
.fr input:focus{border-color:#0891b2;outline:none}
|
|
.badge{padding:3px 8px;border-radius:4px;font-size:11px;font-weight:600}
|
|
.badge-on{background:rgba(16,185,129,.15);color:#10b981}.badge-off{background:rgba(239,68,68,.15);color:#ef4444}
|
|
.toast{position:fixed;top:20px;right:20px;padding:12px 20px;border-radius:8px;color:#fff;font-weight:600;z-index:10000;animation:si .3s}
|
|
@keyframes si{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}
|
|
</style></head><body>
|
|
<div class="hdr">
|
|
<h1><i class="fa fa-sliders"></i> Menus & Quick Access Admin</h1>
|
|
<div style="display:flex;gap:10px">
|
|
<button class="btn bg" onclick="seedDefaults()"><i class="fa fa-download"></i> Seed Defaults</button>
|
|
<button class="btn by" onclick="applyChanges()"><i class="fa fa-bolt"></i> Apply to UI</button>
|
|
<a href="/dashboard.html" class="back"><i class="fa fa-arrow-left"></i> Dashboard</a>
|
|
</div></div>
|
|
<div class="container">
|
|
<div class="metrics">
|
|
<div class="mc"><div class="l"><i class="fa fa-microchip"></i> CPU</div><div class="v <?=mclass($cpu)?>"><?=number_format($cpu,1)?>%</div><div class="bar"><div class="bf" style="width:<?=$cpu?>%;background:<?=mcolor($cpu)?>"></div></div></div>
|
|
<div class="mc"><div class="l"><i class="fa fa-memory"></i> RAM</div><div class="v <?=mclass($ram)?>"><?=number_format($ram,1)?>%</div><div class="bar"><div class="bf" style="width:<?=$ram?>%;background:<?=mcolor($ram)?>"></div></div></div>
|
|
<div class="mc"><div class="l"><i class="fa fa-hard-drive"></i> Storage</div><div class="v <?=mclass($storage,80,60)?>"><?=$storage?>%</div><div class="bar"><div class="bf" style="width:<?=$storage?>%;background:<?=mcolor($storage,80,60)?>"></div></div></div>
|
|
<div class="mc"><div class="l"><i class="fa fa-satellite-dish"></i> Tracking</div><div class="v green" id="tv">...</div><div class="bar"><div class="bf" id="tb" style="width:0%;background:#10b981"></div></div></div>
|
|
</div>
|
|
<div class="tabs">
|
|
<button class="tab active" onclick="stab('footer',this)"><i class="fa fa-bars"></i> Footer Quick Access</button>
|
|
<button class="tab" onclick="stab('header_quick',this)"><i class="fa fa-th-large"></i> Header Quick Access</button>
|
|
<button class="tab" onclick="stab('header_cloud',this)"><i class="fa fa-cloud"></i> Header Cloud</button>
|
|
</div>
|
|
<?php
|
|
$secNames=['footer'=>['Footer Quick Access Popup','fa-bars'],'header_quick'=>['Header Quick Access Dropdown','fa-th-large'],'header_cloud'=>['Header Cloud Dropdown','fa-cloud']];
|
|
foreach($secNames as $sec=>$info):?>
|
|
<div class="sp<?=$sec==='footer'?' active':''?>" id="p-<?=$sec?>">
|
|
<div class="sh"><h3><i class="fa <?=$info[1]?>"></i> <?=$info[0]?></h3><button class="btn bc" onclick="document.getElementById('f-<?=$sec?>').classList.toggle('vis')"><i class="fa fa-plus"></i> Add</button></div>
|
|
<table><thead><tr><th>Icon</th><th>Label</th><th>URL</th><th>Order</th><th>Status</th><th>Actions</th></tr></thead><tbody id="tb-<?=$sec?>">
|
|
<?php if(!empty($secs[$sec])):foreach($secs[$sec] as $it):?>
|
|
<tr id="r-<?=$it['id']?>"><td><div class="ip"><i class="fa <?=htmlspecialchars($it['icon'])?>"></i></div></td>
|
|
<td><strong><?=htmlspecialchars($it['label'])?></strong></td>
|
|
<td style="color:#64748b;font-size:12px"><?=htmlspecialchars($it['url'])?></td>
|
|
<td><?=$it['sort_order']?></td>
|
|
<td><span class="badge <?=$it['is_active']?'badge-on':'badge-off'?>"><?=$it['is_active']?'Active':'Off'?></span></td>
|
|
<td style="display:flex;gap:5px"><button class="btn bs by" onclick="tog(<?=$it['id']?>)"><i class="fa fa-power-off"></i></button><button class="btn bs br" onclick="del(<?=$it['id']?>)"><i class="fa fa-trash"></i></button></td></tr>
|
|
<?php endforeach;else:?>
|
|
<tr><td colspan="6" style="text-align:center;color:#64748b;padding:30px">No items — click "Seed Defaults" to populate</td></tr>
|
|
<?php endif;?></tbody></table>
|
|
<div class="af" id="f-<?=$sec?>"><div class="fr">
|
|
<input placeholder="fa-icon" id="i-<?=$sec?>" value="fa-link">
|
|
<input placeholder="Label" id="l-<?=$sec?>">
|
|
<input placeholder="URL (relative)" id="u-<?=$sec?>">
|
|
<input type="number" placeholder="#" id="o-<?=$sec?>" value="0">
|
|
<span></span>
|
|
<button class="btn bg" onclick="add('<?=$sec?>')"><i class="fa fa-check"></i> Save</button>
|
|
</div></div></div>
|
|
<?php endforeach;?>
|
|
</div>
|
|
<script>
|
|
function stab(s,el){document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));document.querySelectorAll('.sp').forEach(p=>p.classList.remove('active'));el.classList.add('active');document.getElementById('p-'+s).classList.add('active')}
|
|
function toast(m,c){var t=document.createElement('div');t.className='toast';t.style.background=c||'#0891b2';t.textContent=m;document.body.appendChild(t);setTimeout(()=>t.remove(),3000)}
|
|
function post(d){return fetch('quick-access-admin.php',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:new URLSearchParams(d)}).then(r=>r.json())}
|
|
function add(s){post({action:'add',section:s,label:document.getElementById('l-'+s).value,url:document.getElementById('u-'+s).value,icon:document.getElementById('i-'+s).value,sort_order:document.getElementById('o-'+s).value}).then(d=>{if(d.success){toast('Added!','#059669');location.reload()}})}
|
|
function del(id){if(!confirm('Delete?'))return;post({action:'delete',id:id}).then(d=>{if(d.success){document.getElementById('r-'+id).remove();toast('Deleted','#dc2626')}})}
|
|
function tog(id){post({action:'toggle',id:id}).then(d=>{if(d.success){toast('Toggled','#d97706');location.reload()}})}
|
|
function seedDefaults(){post({action:'seed_defaults'}).then(d=>{if(d.success){toast('Seeded '+d.seeded+' items!','#059669');location.reload()}else toast(d.message||'Error','#d97706')})}
|
|
function applyChanges(){if(!confirm('Apply changes to master.html & footer JS?'))return;post({action:'apply'}).then(d=>{if(d.success)toast('Applied! '+d.results.join(', '),'#059669');else toast('Error','#dc2626')})}
|
|
fetch('/api/tracking-status.php').then(r=>r.json()).then(d=>{document.getElementById('tv').textContent=d.online?'ONLINE':'OFFLINE';document.getElementById('tv').className='v '+(d.online?'green':'red');document.getElementById('tb').style.width=d.online?'100%':'0%'}).catch(()=>{});
|
|
</script></body></html>
|