fix(admin): noindex korrekt via params, Test-Datei entfernt
noindex muss unter params: stehen (Hextra liest .Params.noindex); als Top-Level-Key wirkungslos. Admin-Seite jetzt noindex, betreiber.md (Test) weg. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -126,7 +126,9 @@
|
||||
const head =
|
||||
'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">' +
|
||||
'<div class="hosting-title" style="text-align:left;margin:0">Mein Konto</div>' +
|
||||
'<button class="hosting-link" id="logout">Abmelden</button></div>' +
|
||||
'<div style="display:flex;gap:14px;align-items:center">' +
|
||||
(account.is_admin ? '<a class="hosting-link" href="/admin/">Admin</a>' : "") +
|
||||
'<button class="hosting-link" id="logout">Abmelden</button></div></div>' +
|
||||
'<div class="hosting-sub" style="text-align:left;margin-bottom:20px">' + esc(account.email) + "</div>" +
|
||||
'<div class="hosting-tabs">' +
|
||||
tabs.map(([id, label]) =>
|
||||
@@ -274,5 +276,54 @@
|
||||
});
|
||||
}
|
||||
|
||||
({ login: renderLogin, register: renderRegister, konto: renderKonto, preise: renderPreise }[page] || renderLogin)();
|
||||
// ── Admin / Betreiber-Bereich ────────────────────────────────────────────
|
||||
async function renderAdmin() {
|
||||
if (!tok.isLoggedIn) return go("/login/");
|
||||
root.innerHTML = card('<div class="hosting-sub">Lädt…</div>', true);
|
||||
let stats, accounts;
|
||||
try {
|
||||
[stats, accounts] = await Promise.all([
|
||||
api("GET", "/admin/stats"),
|
||||
api("GET", "/admin/accounts"),
|
||||
]);
|
||||
} catch (err) {
|
||||
if (/angemeldet|abgelaufen|ungültig/i.test(err.message)) { tok.clear(); return go("/login/"); }
|
||||
// 403 = eingeloggt, aber kein Admin
|
||||
root.innerHTML = card('<div class="hosting-msg err">' + esc(err.message) + "</div>" +
|
||||
'<a class="hosting-link" href="/konto/">Zurück zum Konto</a>');
|
||||
return;
|
||||
}
|
||||
|
||||
const stat = (label, val) =>
|
||||
'<div class="admin-stat"><div class="admin-stat-num">' + esc(val) + "</div>" +
|
||||
'<div class="admin-stat-label">' + label + "</div></div>";
|
||||
|
||||
const rows = accounts.accounts.map((a) =>
|
||||
"<tr>" +
|
||||
"<td><b>" + esc(a.email) + "</b>" + (a.is_admin ? ' <span class="admin-tag">Admin</span>' : "") +
|
||||
(a.company ? '<div class="muted" style="font-size:12px">' + esc(a.company) + "</div>" : "") + "</td>" +
|
||||
"<td>" + (a.plan ? esc(a.plan) + '<div class="muted" style="font-size:12px">' + esc(a.sub_status || "") + "</div>" : '<span class="muted">—</span>') + "</td>" +
|
||||
"<td style=\"text-align:center\">" + esc(a.instance_count) + "</td>" +
|
||||
"<td class=\"muted\" style=\"font-size:12px\">" + esc(new Date(a.created_at).toLocaleDateString("de-CH")) + "</td>" +
|
||||
"</tr>"
|
||||
).join("");
|
||||
|
||||
const html =
|
||||
'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px">' +
|
||||
'<div class="hosting-title" style="text-align:left;margin:0">Admin</div>' +
|
||||
'<a class="hosting-link" href="/konto/">Mein Konto</a></div>' +
|
||||
'<div class="admin-stats">' +
|
||||
stat("Kunden", stats.accounts) +
|
||||
stat("Aktive Abos", stats.activeSubscriptions) +
|
||||
stat("Instanzen", stats.activeInstances + "/" + stats.instances) +
|
||||
stat("MRR (CHF)", stats.mrrChf) +
|
||||
"</div>" +
|
||||
'<div style="margin:24px 0 10px;font-weight:600;font-size:14px">Kunden</div>' +
|
||||
'<table class="admin-table"><thead><tr><th>Konto</th><th>Abo</th><th>Inst.</th><th>Seit</th></tr></thead>' +
|
||||
"<tbody>" + (rows || '<tr><td colspan="4" class="muted">Noch keine Kunden.</td></tr>') + "</tbody></table>";
|
||||
|
||||
root.innerHTML = card(html, true);
|
||||
}
|
||||
|
||||
({ login: renderLogin, register: renderRegister, konto: renderKonto, preise: renderPreise, admin: renderAdmin }[page] || renderLogin)();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user