diff --git a/panel/api/endpoints/email.php b/panel/api/endpoints/email.php index efafe6b..09b99ab 100644 --- a/panel/api/endpoints/email.php +++ b/panel/api/endpoints/email.php @@ -98,5 +98,21 @@ match ($action) { Response::success(null, 'Autoresponder deleted'); })(), + + 'domains' => (function() use ($db) { + Auth::getInstance()->require('admin', 'reseller'); + $user = Auth::getInstance()->user(); + $clause = $user['role'] === 'reseller' ? "AND a.user_id IN (SELECT id FROM users WHERE reseller_id=".(int)$user['uid'].")" : ""; + $rows = $db->fetchAll( + "SELECT d.domain, a.username, a.id as account_id, + (SELECT COUNT(*) FROM email_accounts WHERE account_id = a.id) as email_count + FROM dns_zones d + JOIN accounts a ON a.id = d.account_id + WHERE 1=1 $clause + ORDER BY d.domain" + ); + Response::success($rows); + })(), + default => Response::error("Unknown email action: $action", 404), }; diff --git a/panel/api/endpoints/system.php b/panel/api/endpoints/system.php index 11b93ca..1d1b1a2 100644 --- a/panel/api/endpoints/system.php +++ b/panel/api/endpoints/system.php @@ -1057,5 +1057,22 @@ BASH; exit; })(), - default => Response::error("Unknown system action: $action", 404), + + 'read-log' => (function() { + Auth::getInstance()->require('admin'); + $log = preg_replace('/[^a-z0-9-]/', '', $_GET['log'] ?? 'panel'); + $map = [ + 'panel' => '/var/log/novacpx/panel.log', + 'deploy' => '/var/log/novacpx/deploy.log', + 'nginx-error' => '/var/log/novacpx/nginx-error.log', + 'nginx-access' => '/var/log/novacpx/nginx-access.log', + 'mail' => '/var/log/mail.log', + 'stats' => '/var/log/novacpx/stats-collector.log', + ]; + $path = $map[$log] ?? '/var/log/novacpx/panel.log'; + $raw = file_exists($path) ? trim(shell_exec('tail -100 ' . escapeshellarg($path)) ?: '') : ''; + Response::success(['content' => $raw, 'log' => $log]); + })(), + + default => Response::error("Unknown system action: $action", 404), }; diff --git a/panel/public/assets/js/admin.js b/panel/public/assets/js/admin.js index 8e8e145..542a291 100644 --- a/panel/public/assets/js/admin.js +++ b/panel/public/assets/js/admin.js @@ -1401,26 +1401,68 @@ // ── Web Server ──────────────────────────────────────────────────────────── async function webServer() { - const r = await Nova.api('system', 'stats'); - const svcs = r?.data?.services || {}; - const webSvc = Object.keys(svcs).find(k => k.includes('apache') || k.includes('nginx')) || 'apache2'; + const [statsR, phpR] = await Promise.all([ + Nova.api('system','stats'), + Nova.api('php','global-config'), + ]); + const svcs = statsR?.data?.services || {}; + const uptime = statsR?.data?.uptime || '—'; + const cpu = statsR?.data?.cpu?.pct ?? '—'; + const ram = statsR?.data?.ram?.pct ?? '—'; + const phpCfg = phpR?.data || {}; + + window.wsLoadLog = async (log) => { + const r = await Nova.api('system','read-log',{params:{log}}); + const el = document.getElementById('ws-log-out'); + if (el) { el.textContent = r?.data?.content || '(empty)'; el.scrollTop = el.scrollHeight; } + }; + return ` -
← Click a log above to view it
No mail services detected
'}| Domain | Account | Email Accounts |
|---|---|---|
| ${Nova.escHtml(d.domain)} | ${Nova.escHtml(d.username||'—')} | ${d.email_count||0} |
← Click Load Log to view recent mail activity
${r?.data?.output || 'Queue is empty'}`);
+ const out = r?.data?.output || 'Queue is empty';
+ const el = document.getElementById('ms-queue-out');
+ if (el) el.innerHTML = `${Nova.escHtml(out)}`;
+ else Nova.modal('Mail Queue', `${Nova.escHtml(out)}`);
};
// ── FTP Server ────────────────────────────────────────────────────────────
@@ -2653,23 +2735,36 @@ ${dbs.map(d=>`Active FTP server: ${label} — change in Server Options.
-FTP connections use SFTP on port 22 or passive FTP on ports 20/21.
-Per-account FTP management is available in each account's FTP page.
-| Username | Account | Directory | Permissions |
|---|---|---|---|
| ${Nova.escHtml(f.username)} | +${Nova.escHtml(f.account_domain||String(f.account_id)||'—')} | +${Nova.escHtml(f.home_dir||'—')} | +${Nova.badge(f.permissions||'rw','blue')} | +