const REASONS = { 'honeypot': 'Антиспам-поле заполнено', 'login-bruteforce': 'Подбор пароля (10 неудачных входов)', 'share-password-bruteforce': 'Подбор пароля ссылки', 'manual': 'Вручную', }; function reasonLabel(r) { return REASONS[r] || r || '—'; } async function loadBans() { const tbody = document.getElementById('bansBody'); const info = document.getElementById('bansInfo'); const res = await fetch(`${API}/api/bans`, { headers: hdr() }); if (!res.ok) { tbody.innerHTML = `Ошибка загрузки (${res.status})`; info.textContent = ''; return; } const bans = await res.json(); info.textContent = `Активных блокировок: ${bans.length}`; if (!bans.length) { tbody.innerHTML = 'Активных блокировок нет'; return; } tbody.innerHTML = bans.map(b => ` ${esc(b.ip)} ${esc(reasonLabel(b.reason))} ${new Date(b.created_at).toLocaleString('ru')} ${new Date(b.banned_until).toLocaleString('ru')} `).join(''); renderIcons(); } document.getElementById('bansBody').addEventListener('click', async e => { const ip = e.target.closest('[data-unban]')?.dataset.unban; if (!ip) return; const btn = e.target.closest('[data-unban]'); btn.disabled = true; const res = await fetch(`${API}/api/bans/${encodeURIComponent(ip)}`, { method: 'DELETE', headers: hdr() }); if (res.ok) showToast('IP разблокирован: ' + ip); else showToast('Ошибка разблокировки'); btn.disabled = false; loadBans(); }); document.getElementById('refreshBtn').addEventListener('click', loadBans); (async () => { if (await requireAdminPage()) { buildSidebar(document.body.dataset.page); loadBans(); } })();