370 lines
23 KiB
PHP
Executable File
370 lines
23 KiB
PHP
Executable File
<?php
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', 0);
|
|
|
|
function getDB() {
|
|
static $pdo = null;
|
|
if ($pdo === null) {
|
|
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123",
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
}
|
|
return $pdo;
|
|
}
|
|
|
|
function ensureTables() {
|
|
$pdo = getDB();
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS admin.warmup_accounts (
|
|
id SERIAL PRIMARY KEY,
|
|
email VARCHAR(255) NOT NULL UNIQUE,
|
|
password VARCHAR(255),
|
|
smtp_host VARCHAR(255),
|
|
smtp_port INTEGER DEFAULT 587,
|
|
imap_host VARCHAR(255),
|
|
imap_port INTEGER DEFAULT 993,
|
|
encryption VARCHAR(20) DEFAULT 'tls',
|
|
provider VARCHAR(100),
|
|
daily_limit INTEGER DEFAULT 50,
|
|
current_day INTEGER DEFAULT 1,
|
|
emails_sent_today INTEGER DEFAULT 0,
|
|
total_sent INTEGER DEFAULT 0,
|
|
reputation_score INTEGER DEFAULT 50,
|
|
status VARCHAR(50) DEFAULT 'active',
|
|
last_sent TIMESTAMP,
|
|
error_message TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)");
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS admin.warmup_schedules (
|
|
id SERIAL PRIMARY KEY,
|
|
day INTEGER UNIQUE,
|
|
emails_count INTEGER
|
|
)");
|
|
|
|
$count = $pdo->query("SELECT COUNT(*) FROM admin.warmup_schedules")->fetchColumn();
|
|
if ($count == 0) {
|
|
$pdo->exec("INSERT INTO admin.warmup_schedules (day, emails_count) VALUES
|
|
(1,5),(2,8),(3,12),(4,18),(5,25),(6,35),(7,50),(14,100),(21,200),(30,350),(45,500),(60,750),(90,1000)");
|
|
}
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS admin.warmup_messages (
|
|
id SERIAL PRIMARY KEY,
|
|
subject VARCHAR(500) NOT NULL,
|
|
body TEXT NOT NULL,
|
|
category VARCHAR(100) DEFAULT 'general',
|
|
is_active BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)");
|
|
|
|
$msgCount = $pdo->query("SELECT COUNT(*) FROM admin.warmup_messages")->fetchColumn();
|
|
if ($msgCount == 0) {
|
|
$pdo->exec("INSERT INTO admin.warmup_messages (subject, body, category) VALUES
|
|
('Meeting follow-up', 'Hi, Just following up on our conversation. Best regards', 'business'),
|
|
('Quick question', 'Hello, I had a quick question about the project. Thanks', 'business'),
|
|
('Thank you', 'Hi there, Thank you for your help! Best', 'personal'),
|
|
('Checking in', 'Hey, Just wanted to check in. Hope all is well!', 'personal')");
|
|
}
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS admin.warmup_logs (
|
|
id SERIAL PRIMARY KEY,
|
|
from_account_id INTEGER,
|
|
to_account_id INTEGER,
|
|
from_email VARCHAR(255),
|
|
to_email VARCHAR(255),
|
|
subject VARCHAR(500),
|
|
status VARCHAR(50) DEFAULT 'sent',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)");
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS admin.warmup_pools (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(100) NOT NULL,
|
|
description TEXT,
|
|
accounts_count INTEGER DEFAULT 0,
|
|
status VARCHAR(50) DEFAULT 'active',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)");
|
|
}
|
|
|
|
if (isset($_GET['action']) || isset($_POST['action'])) {
|
|
header('Content-Type: application/json');
|
|
ensureTables();
|
|
$action = $_GET['action'] ?? $_POST['action'];
|
|
$pdo = getDB();
|
|
|
|
try {
|
|
switch ($action) {
|
|
case 'stats':
|
|
echo json_encode(['success' => true, 'stats' => [
|
|
'total' => $pdo->query("SELECT COUNT(*) FROM admin.warmup_accounts")->fetchColumn(),
|
|
'active' => $pdo->query("SELECT COUNT(*) FROM admin.warmup_accounts WHERE status = 'active'")->fetchColumn(),
|
|
'today' => $pdo->query("SELECT COALESCE(SUM(emails_sent_today), 0) FROM admin.warmup_accounts")->fetchColumn(),
|
|
'total_sent' => $pdo->query("SELECT COALESCE(SUM(total_sent), 0) FROM admin.warmup_accounts")->fetchColumn(),
|
|
'avg_rep' => round($pdo->query("SELECT COALESCE(AVG(reputation_score), 50) FROM admin.warmup_accounts")->fetchColumn()),
|
|
'pools' => $pdo->query("SELECT COUNT(*) FROM admin.warmup_pools")->fetchColumn(),
|
|
]]);
|
|
break;
|
|
|
|
case 'list_accounts':
|
|
$accounts = $pdo->query("SELECT * FROM admin.warmup_accounts ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'accounts' => $accounts]);
|
|
break;
|
|
|
|
case 'add_account':
|
|
$stmt = $pdo->prepare("INSERT INTO admin.warmup_accounts (email, password, smtp_host, smtp_port, imap_host, imap_port, provider) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT (email) DO NOTHING RETURNING id");
|
|
$stmt->execute([$_POST['email'], $_POST['password'], $_POST['smtp_host'], $_POST['smtp_port'] ?? 587, $_POST['imap_host'], $_POST['imap_port'] ?? 993, $_POST['provider'] ?? 'custom']);
|
|
echo json_encode(['success' => true, 'id' => $stmt->fetchColumn()]);
|
|
break;
|
|
|
|
case 'delete_account':
|
|
$pdo->exec("DELETE FROM admin.warmup_accounts WHERE id = " . intval($_POST['id']));
|
|
echo json_encode(['success' => true]);
|
|
break;
|
|
|
|
case 'get_schedule':
|
|
$schedule = $pdo->query("SELECT * FROM admin.warmup_schedules ORDER BY day")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'schedule' => $schedule]);
|
|
break;
|
|
|
|
case 'list_messages':
|
|
$messages = $pdo->query("SELECT * FROM admin.warmup_messages ORDER BY id")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'messages' => $messages]);
|
|
break;
|
|
|
|
case 'add_message':
|
|
$stmt = $pdo->prepare("INSERT INTO admin.warmup_messages (subject, body, category) VALUES (?, ?, ?)");
|
|
$stmt->execute([$_POST['subject'], $_POST['body'], $_POST['category'] ?? 'general']);
|
|
echo json_encode(['success' => true]);
|
|
break;
|
|
|
|
case 'delete_message':
|
|
$pdo->exec("DELETE FROM admin.warmup_messages WHERE id = " . intval($_POST['id']));
|
|
echo json_encode(['success' => true]);
|
|
break;
|
|
|
|
case 'list_pools':
|
|
$pools = $pdo->query("SELECT * FROM admin.warmup_pools ORDER BY id")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'pools' => $pools]);
|
|
break;
|
|
|
|
case 'create_pool':
|
|
$stmt = $pdo->prepare("INSERT INTO admin.warmup_pools (name, description) VALUES (?, ?) RETURNING id");
|
|
$stmt->execute([$_POST['name'], $_POST['description'] ?? '']);
|
|
echo json_encode(['success' => true, 'id' => $stmt->fetchColumn()]);
|
|
break;
|
|
|
|
case 'get_logs':
|
|
$logs = $pdo->query("SELECT * FROM admin.warmup_logs ORDER BY created_at DESC LIMIT 100")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'logs' => $logs]);
|
|
break;
|
|
|
|
case 'reset_daily':
|
|
$pdo->exec("UPDATE admin.warmup_accounts SET current_day = current_day + 1, emails_sent_today = 0 WHERE status = 'active'");
|
|
echo json_encode(['success' => true]);
|
|
break;
|
|
|
|
default:
|
|
echo json_encode(['success' => false, 'error' => 'Unknown action']);
|
|
}
|
|
} catch (Exception $e) {
|
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
|
}
|
|
exit;
|
|
}
|
|
|
|
ensureTables();
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Warmup System</title>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<style>
|
|
:root{--bg:#0a0a0f;--bg2:#12121a;--bg3:#1a1a25;--primary:#6366f1;--success:#10b981;--warning:#f59e0b;--danger:#ef4444;--text:#e2e8f0;--text2:#94a3b8;--border:#2a2a3a;--fire:#ff6b35}
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);min-height:100vh}
|
|
.header{background:linear-gradient(135deg,#1a0a0f,#2a1a1f);border-bottom:1px solid var(--border);padding:1rem 2rem;display:flex;justify-content:space-between;align-items:center}
|
|
.header h1{font-size:1.3rem;display:flex;align-items:center;gap:.5rem;color:var(--fire)}
|
|
.badge-v{background:linear-gradient(135deg,var(--fire),#ff8c42);padding:.25rem .75rem;border-radius:15px;font-size:.7rem;font-weight:700}
|
|
.container{max-width:1400px;margin:0 auto;padding:1.5rem}
|
|
.stats{display:grid;grid-template-columns:repeat(6,1fr);gap:1rem;margin-bottom:1.5rem}
|
|
.stat{background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:1rem;text-align:center}
|
|
.stat .v{font-size:1.6rem;font-weight:700;color:var(--fire)}.stat .l{color:var(--text2);font-size:.7rem}
|
|
.tabs{display:flex;gap:.5rem;margin-bottom:1.5rem}
|
|
.tab{padding:.6rem 1.2rem;background:var(--bg2);border:1px solid var(--border);border-radius:8px;cursor:pointer;font-size:.85rem;transition:all .2s}
|
|
.tab:hover{border-color:var(--fire)}.tab.active{background:linear-gradient(135deg,var(--fire),#ff8c42);border-color:transparent;color:white}
|
|
.panel{display:none}.panel.active{display:block}
|
|
.card{background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:1.25rem;margin-bottom:1rem}
|
|
.card h3{margin-bottom:1rem;font-size:1rem;display:flex;align-items:center;gap:.5rem}
|
|
.form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:.75rem;margin-bottom:1rem}
|
|
.form-group{display:flex;flex-direction:column;gap:.25rem}
|
|
.form-group label{font-size:.7rem;color:var(--text2)}
|
|
.form-group input,.form-group select,.form-group textarea{padding:.5rem .7rem;background:var(--bg3);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.8rem}
|
|
.form-group textarea{min-height:80px}
|
|
.btn{padding:.5rem 1rem;border:none;border-radius:6px;font-weight:600;cursor:pointer;transition:all .2s;display:inline-flex;align-items:center;gap:.4rem;font-size:.8rem}
|
|
.btn:hover{transform:translateY(-1px)}.btn-fire{background:linear-gradient(135deg,var(--fire),#ff8c42);color:white}
|
|
.btn-primary{background:var(--primary);color:white}.btn-success{background:var(--success);color:white}.btn-danger{background:var(--danger);color:white}
|
|
.btn-sm{padding:.35rem .6rem;font-size:.75rem}
|
|
table{width:100%;border-collapse:collapse;font-size:.8rem}
|
|
th,td{padding:.5rem;text-align:left;border-bottom:1px solid var(--border)}
|
|
th{color:var(--text2);font-weight:500;font-size:.7rem}
|
|
.badge{padding:.2rem .5rem;border-radius:10px;font-size:.65rem;font-weight:600}
|
|
.badge-active{background:rgba(16,185,129,.15);color:var(--success)}
|
|
.badge-paused{background:rgba(245,158,11,.15);color:var(--warning)}
|
|
.reputation{width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.8rem}
|
|
.rep-good{background:rgba(16,185,129,.2);color:var(--success);border:2px solid var(--success)}
|
|
.rep-medium{background:rgba(245,158,11,.2);color:var(--warning);border:2px solid var(--warning)}
|
|
.rep-bad{background:rgba(239,68,68,.2);color:var(--danger);border:2px solid var(--danger)}
|
|
.progress{height:6px;background:var(--bg3);border-radius:3px;overflow:hidden}.progress-fill{height:100%;background:linear-gradient(90deg,var(--fire),#ff8c42);border-radius:3px}
|
|
.schedule-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(80px,1fr));gap:.5rem}
|
|
.schedule-item{background:var(--bg3);border-radius:6px;padding:.5rem;text-align:center}
|
|
.schedule-item .day{font-size:.65rem;color:var(--text2)}.schedule-item .count{font-size:1rem;font-weight:700;color:var(--fire)}
|
|
.empty{text-align:center;padding:2rem;color:var(--text2)}
|
|
.action-bar{display:flex;gap:.75rem;margin-bottom:1rem}
|
|
.modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,.8);z-index:100;align-items:center;justify-content:center}
|
|
.modal.active{display:flex}
|
|
.modal-content{background:var(--bg2);border-radius:12px;padding:1.5rem;width:500px;max-width:90%}
|
|
.modal-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem}
|
|
.modal-close{background:none;border:none;color:var(--text2);font-size:1.2rem;cursor:pointer}
|
|
</style>
|
|
|
|
</head>
|
|
<body>
|
|
<div class="header"><h1><i class="fas fa-fire"></i> Warmup System</h1><span class="badge-v">v2.0</span></div>
|
|
<div class="container">
|
|
<div class="stats">
|
|
<div class="stat"><div class="v" id="sTotal">0</div><div class="l">Total</div></div>
|
|
<div class="stat"><div class="v" id="sActive">0</div><div class="l">Active</div></div>
|
|
<div class="stat"><div class="v" id="sToday">0</div><div class="l">Today</div></div>
|
|
<div class="stat"><div class="v" id="sSent">0</div><div class="l">Total Sent</div></div>
|
|
<div class="stat"><div class="v" id="sRep">0</div><div class="l">Avg Rep</div></div>
|
|
<div class="stat"><div class="v" id="sPools">0</div><div class="l">Pools</div></div>
|
|
</div>
|
|
|
|
<div class="tabs">
|
|
<div class="tab active" data-tab="accounts"><i class="fas fa-users"></i> Accounts</div>
|
|
<div class="tab" data-tab="schedule"><i class="fas fa-calendar"></i> Schedule</div>
|
|
<div class="tab" data-tab="messages"><i class="fas fa-envelope"></i> Messages</div>
|
|
<div class="tab" data-tab="pools"><i class="fas fa-layer-group"></i> Pools</div>
|
|
<div class="tab" data-tab="logs"><i class="fas fa-history"></i> Logs</div>
|
|
</div>
|
|
|
|
<div class="panel active" id="panel-accounts">
|
|
<div class="action-bar">
|
|
<button class="btn btn-fire" onclick="showAddAccount()"><i class="fas fa-plus"></i> Add Account</button>
|
|
<button class="btn btn-warning" onclick="resetDaily()"><i class="fas fa-redo"></i> Reset Daily</button>
|
|
</div>
|
|
<div class="card">
|
|
<h3><i class="fas fa-fire"></i> Warmup Accounts</h3>
|
|
<table>
|
|
<thead><tr><th>Email</th><th>Provider</th><th>Day</th><th>Today</th><th>Progress</th><th>Rep</th><th>Status</th><th>Actions</th></tr></thead>
|
|
<tbody id="accountsTable"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel" id="panel-schedule">
|
|
<div class="card">
|
|
<h3><i class="fas fa-calendar"></i> Warmup Schedule</h3>
|
|
<div class="schedule-grid" id="scheduleGrid"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel" id="panel-messages">
|
|
<div class="card">
|
|
<h3><i class="fas fa-plus"></i> Add Template</h3>
|
|
<div class="form-row">
|
|
<div class="form-group"><label>Subject</label><input type="text" id="msgSubject"></div>
|
|
<div class="form-group"><label>Category</label><select id="msgCategory"><option value="business">Business</option><option value="personal">Personal</option></select></div>
|
|
</div>
|
|
<div class="form-group"><label>Body</label><textarea id="msgBody"></textarea></div>
|
|
<button class="btn btn-fire" onclick="addMessage()"><i class="fas fa-plus"></i> Add</button>
|
|
</div>
|
|
<div class="card">
|
|
<h3><i class="fas fa-envelope"></i> Templates</h3>
|
|
<table><thead><tr><th>Subject</th><th>Category</th><th>Actions</th></tr></thead><tbody id="messagesTable"></tbody></table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel" id="panel-pools">
|
|
<div class="card">
|
|
<h3><i class="fas fa-plus"></i> Create Pool</h3>
|
|
<div class="form-row">
|
|
<div class="form-group"><label>Name</label><input type="text" id="poolName"></div>
|
|
<div class="form-group"><label>Description</label><input type="text" id="poolDesc"></div>
|
|
<div class="form-group"><label> </label><button class="btn btn-fire" onclick="createPool()"><i class="fas fa-plus"></i> Create</button></div>
|
|
</div>
|
|
</div>
|
|
<div class="card">
|
|
<h3><i class="fas fa-layer-group"></i> Pools</h3>
|
|
<table><thead><tr><th>Name</th><th>Description</th><th>Members</th><th>Status</th></tr></thead><tbody id="poolsTable"></tbody></table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel" id="panel-logs">
|
|
<div class="card">
|
|
<h3><i class="fas fa-history"></i> Recent Logs</h3>
|
|
<div id="logsContainer"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal" id="addAccountModal">
|
|
<div class="modal-content">
|
|
<div class="modal-header"><h3>Add Account</h3><button class="modal-close" onclick="closeModal()">×</button></div>
|
|
<div class="form-row">
|
|
<div class="form-group"><label>Email</label><input type="email" id="accEmail"></div>
|
|
<div class="form-group"><label>Password</label><input type="password" id="accPassword"></div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-group"><label>SMTP Host</label><input type="text" id="accSmtpHost" value="smtp.gmail.com"></div>
|
|
<div class="form-group"><label>SMTP Port</label><input type="number" id="accSmtpPort" value="587"></div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-group"><label>IMAP Host</label><input type="text" id="accImapHost" value="imap.gmail.com"></div>
|
|
<div class="form-group"><label>IMAP Port</label><input type="number" id="accImapPort" value="993"></div>
|
|
</div>
|
|
<div class="form-group"><label>Provider</label><select id="accProvider"><option value="gmail">Gmail</option><option value="outlook">Outlook</option><option value="custom">Custom</option></select></div>
|
|
<button class="btn btn-fire" onclick="addAccount()" style="margin-top:1rem"><i class="fas fa-plus"></i> Add</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.querySelectorAll('.tab').forEach(t=>{t.onclick=()=>{document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active'));document.querySelectorAll('.panel').forEach(p=>p.classList.remove('active'));t.classList.add('active');document.getElementById('panel-'+t.dataset.tab).classList.add('active');if(t.dataset.tab==='schedule')loadSchedule();if(t.dataset.tab==='messages')loadMessages();if(t.dataset.tab==='pools')loadPools();if(t.dataset.tab==='logs')loadLogs();}});
|
|
|
|
function loadStats(){fetch('?action=stats').then(r=>r.json()).then(d=>{if(d.success){document.getElementById('sTotal').textContent=d.stats.total;document.getElementById('sActive').textContent=d.stats.active;document.getElementById('sToday').textContent=d.stats.today;document.getElementById('sSent').textContent=Number(d.stats.total_sent).toLocaleString();document.getElementById('sRep').textContent=d.stats.avg_rep;document.getElementById('sPools').textContent=d.stats.pools;}});}
|
|
|
|
function loadAccounts(){fetch('?action=list_accounts').then(r=>r.json()).then(d=>{if(d.success){document.getElementById('accountsTable').innerHTML=d.accounts.length?d.accounts.map(a=>{const repClass=a.reputation_score>=70?'rep-good':(a.reputation_score>=40?'rep-medium':'rep-bad');const prog=Math.min(100,(a.current_day/90)*100);return`<tr><td><strong>${a.email}</strong></td><td>${a.provider||'custom'}</td><td>Day ${a.current_day}</td><td>${a.emails_sent_today}/${a.daily_limit||50}</td><td style="width:80px"><div class="progress"><div class="progress-fill" style="width:${prog}%"></div></div></td><td><div class="reputation ${repClass}">${a.reputation_score}</div></td><td><span class="badge badge-${a.status}">${a.status}</span></td><td><button class="btn btn-danger btn-sm" onclick="deleteAccount(${a.id})"><i class="fas fa-trash"></i></button></td></tr>`;}).join(''):'<tr><td colspan="8" class="empty">No accounts</td></tr>';}});}
|
|
|
|
function loadSchedule(){fetch('?action=get_schedule').then(r=>r.json()).then(d=>{if(d.success){document.getElementById('scheduleGrid').innerHTML=d.schedule.map(s=>`<div class="schedule-item"><div class="day">Day ${s.day}</div><div class="count">${s.emails_count}</div></div>`).join('');}});}
|
|
|
|
function loadMessages(){fetch('?action=list_messages').then(r=>r.json()).then(d=>{if(d.success){document.getElementById('messagesTable').innerHTML=d.messages.map(m=>`<tr><td>${m.subject}</td><td>${m.category}</td><td><button class="btn btn-danger btn-sm" onclick="deleteMessage(${m.id})"><i class="fas fa-trash"></i></button></td></tr>`).join('');}});}
|
|
|
|
function loadPools(){fetch('?action=list_pools').then(r=>r.json()).then(d=>{if(d.success){document.getElementById('poolsTable').innerHTML=d.pools.length?d.pools.map(p=>`<tr><td>${p.name}</td><td>${p.description||'-'}</td><td>${p.accounts_count}</td><td><span class="badge badge-${p.status}">${p.status}</span></td></tr>`).join(''):'<tr><td colspan="4" class="empty">No pools</td></tr>';}});}
|
|
|
|
function loadLogs(){fetch('?action=get_logs').then(r=>r.json()).then(d=>{if(d.success){document.getElementById('logsContainer').innerHTML=d.logs.length?d.logs.map(l=>`<div style="padding:.4rem;background:var(--bg3);border-radius:4px;margin-bottom:.25rem;font-size:.75rem"><i class="fas fa-paper-plane" style="color:var(--fire)"></i> ${l.from_email} → ${l.to_email} <span style="color:var(--text2);float:right">${new Date(l.created_at).toLocaleString()}</span></div>`).join(''):'<div class="empty">No logs</div>';}});}
|
|
|
|
function showAddAccount(){document.getElementById('addAccountModal').classList.add('active');}
|
|
function closeModal(){document.getElementById('addAccountModal').classList.remove('active');}
|
|
|
|
function addAccount(){const fd=new FormData();fd.append('action','add_account');fd.append('email',document.getElementById('accEmail').value);fd.append('password',document.getElementById('accPassword').value);fd.append('smtp_host',document.getElementById('accSmtpHost').value);fd.append('smtp_port',document.getElementById('accSmtpPort').value);fd.append('imap_host',document.getElementById('accImapHost').value);fd.append('imap_port',document.getElementById('accImapPort').value);fd.append('provider',document.getElementById('accProvider').value);fetch('',{method:'POST',body:fd}).then(r=>r.json()).then(d=>{if(d.success){alert('Added!');closeModal();loadAccounts();loadStats();}});}
|
|
|
|
function deleteAccount(id){if(!confirm('Delete?'))return;const fd=new FormData();fd.append('action','delete_account');fd.append('id',id);fetch('',{method:'POST',body:fd}).then(()=>{loadAccounts();loadStats();});}
|
|
|
|
function addMessage(){const fd=new FormData();fd.append('action','add_message');fd.append('subject',document.getElementById('msgSubject').value);fd.append('body',document.getElementById('msgBody').value);fd.append('category',document.getElementById('msgCategory').value);fetch('',{method:'POST',body:fd}).then(()=>loadMessages());}
|
|
|
|
function deleteMessage(id){if(!confirm('Delete?'))return;const fd=new FormData();fd.append('action','delete_message');fd.append('id',id);fetch('',{method:'POST',body:fd}).then(()=>loadMessages());}
|
|
|
|
function createPool(){const fd=new FormData();fd.append('action','create_pool');fd.append('name',document.getElementById('poolName').value);fd.append('description',document.getElementById('poolDesc').value);fetch('',{method:'POST',body:fd}).then(()=>{loadPools();loadStats();});}
|
|
|
|
function resetDaily(){if(!confirm('Reset daily counters?'))return;const fd=new FormData();fd.append('action','reset_daily');fetch('',{method:'POST',body:fd}).then(()=>{loadAccounts();loadStats();});}
|
|
|
|
loadStats();
|
|
loadAccounts();
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|