jtl-wafi-dashboard.py aktualisiert

This commit is contained in:
2025-12-30 12:56:21 +01:00
parent b6a82f8097
commit 2e1665ebda

View File

@@ -954,7 +954,8 @@ async def activate_shop(
country_rate_limit: int = Form(100),
country_ban_duration: int = Form(600),
unlimited_countries: str = Form(""),
monitor_only: str = Form("false")
monitor_only: str = Form("false"),
restart_fpm: str = Form("false")
):
"""Aktiviert Blocking für einen Shop (v2.5)."""
user = await get_current_user(request)
@@ -965,6 +966,7 @@ async def activate_shop(
is_bot_mode = bot_mode.lower() in ('true', '1', 'yes', 'on')
is_country_mode = country_mode.lower() in ('true', '1', 'yes', 'on')
is_monitor_only = monitor_only.lower() in ('true', '1', 'yes', 'on')
is_restart_fpm = restart_fpm.lower() in ('true', '1', 'yes', 'on')
# unlimited_countries als Liste parsen
countries_list = []
@@ -988,7 +990,8 @@ async def activate_shop(
'country_rate_limit': country_rate_limit if is_country_mode else None,
'country_ban_duration': country_ban_duration if is_country_mode else None,
'unlimited_countries': countries_list if is_country_mode else [],
'monitor_only': is_monitor_only
'monitor_only': is_monitor_only,
'restart_fpm': is_restart_fpm
}
})
@@ -996,11 +999,17 @@ async def activate_shop(
@app.post("/api/shops/deactivate")
async def deactivate_shop(request: Request, domain: str = Form(...)):
async def deactivate_shop(
request: Request,
domain: str = Form(...),
restart_fpm: str = Form("false")
):
user = await get_current_user(request)
if not user:
raise HTTPException(401)
is_restart_fpm = restart_fpm.lower() in ('true', '1', 'yes', 'on')
agent_id = manager.get_agent_for_shop(domain)
if not agent_id or not manager.is_agent_connected(agent_id):
return JSONResponse({"success": False, "error": "Agent nicht verbunden"})
@@ -1008,7 +1017,11 @@ async def deactivate_shop(request: Request, domain: str = Form(...)):
command_id = secrets.token_hex(8)
await manager.send_to_agent(agent_id, {
'type': 'command.deactivate',
'data': {'command_id': command_id, 'shop': domain}
'data': {
'command_id': command_id,
'shop': domain,
'restart_fpm': is_restart_fpm
}
})
return {"success": True, "command_id": command_id}
@@ -1025,7 +1038,8 @@ async def bulk_activate(
country_ban_duration: int = Form(600),
unlimited_countries: str = Form(""),
monitor_only: str = Form("false"),
filter_type: str = Form("all")
filter_type: str = Form("all"),
restart_fpm: str = Form("false")
):
"""Bulk-Aktivierung für mehrere Shops (v2.5)."""
user = await get_current_user(request)
@@ -1036,6 +1050,7 @@ async def bulk_activate(
is_bot_mode = bot_mode.lower() in ('true', '1', 'yes', 'on')
is_country_mode = country_mode.lower() in ('true', '1', 'yes', 'on')
is_monitor_only = monitor_only.lower() in ('true', '1', 'yes', 'on')
is_restart_fpm = restart_fpm.lower() in ('true', '1', 'yes', 'on')
# unlimited_countries als Liste parsen
countries_list = []
@@ -1071,7 +1086,8 @@ async def bulk_activate(
'country_rate_limit': country_rate_limit if is_country_mode else None,
'country_ban_duration': country_ban_duration if is_country_mode else None,
'unlimited_countries': countries_list if is_country_mode else [],
'monitor_only': is_monitor_only
'monitor_only': is_monitor_only,
'restart_fpm': is_restart_fpm
}
})
activated += 1
@@ -1084,11 +1100,17 @@ async def bulk_activate(
@app.post("/api/shops/bulk-deactivate")
async def bulk_deactivate(request: Request, filter_type: str = Form("all")):
async def bulk_deactivate(
request: Request,
filter_type: str = Form("all"),
restart_fpm: str = Form("false")
):
user = await get_current_user(request)
if not user:
raise HTTPException(401)
is_restart_fpm = restart_fpm.lower() in ('true', '1', 'yes', 'on')
deactivated = 0
shops = store.get_all_shops()
@@ -1108,7 +1130,11 @@ async def bulk_deactivate(request: Request, filter_type: str = Form("all")):
command_id = secrets.token_hex(8)
await manager.send_to_agent(agent_id, {
'type': 'command.deactivate',
'data': {'command_id': command_id, 'shop': shop['domain']}
'data': {
'command_id': command_id,
'shop': shop['domain'],
'restart_fpm': is_restart_fpm
}
})
deactivated += 1
@@ -1359,7 +1385,7 @@ def get_dashboard_html() -> str:
<div class="header-right">
<div class="clock" id="clock">--:--:--</div>
<div class="connection-status"><div class="status-dot" id="wsStatus"></div><span id="wsStatusText">Verbinde...</span></div>
<div style="display:flex;align-items:center;gap:8px"><span style="font-size:12px;color:var(--text-secondary)">Update:</span><select id="updateInterval" onchange="setUpdateInterval(this.value)" style="padding:4px 8px;border-radius:4px;border:1px solid var(--border);background:var(--card-bg);color:var(--text);font-size:12px"><option value="2000">2s</option><option value="5000">5s</option><option value="10000" selected>10s</option><option value="15000">15s</option></select></div>
<div style="display:flex;align-items:center;gap:8px"><span style="font-size:12px;color:var(--text-secondary)">Update:</span><select id="updateInterval" onchange="setUpdateInterval(this.value)" style="padding:4px 8px;border-radius:4px;border:1px solid var(--border);background:var(--card-bg);color:var(--text);font-size:12px"><option value="2000">2s</option><option value="5000">5s</option><option value="10000" selected>10s</option><option value="15000">15s</option></select></div><div style="display:flex;align-items:center;gap:6px;padding:4px 8px;border-radius:4px;border:1px solid var(--border);background:var(--card-bg)"><label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:12px;color:var(--text-secondary)" title="OPcache nach Aktivierung/Deaktivierung leeren"><input type="checkbox" id="autoFpmRestart" checked style="margin:0"><span>FPM-Restart</span></label></div>
<div style="display:flex;gap:8px"><button class="btn-header" onclick="openPasswordModal()">🔑</button><a href="/logout" class="btn-header">Abmelden</a></div>
</div>
</header>
@@ -1435,16 +1461,16 @@ def get_dashboard_html() -> str:
function toggleBotOptions(){const isBot=document.getElementById('botModeCheck').checked;document.getElementById('botOptionsGroup').style.display=isBot?'block':'none';}
function toggleCountryOptions(){const isCountry=document.getElementById('countryModeCheck').checked;document.getElementById('countryOptionsGroup').style.display=isCountry?'block':'none';}
function setCountries(preset){const input=document.querySelector('#activateForm input[name="unlimited_countries"]');if(preset==='dach')input.value='de,at,ch';else if(preset==='eu_plus')input.value='de,at,ch,be,cy,ee,es,fi,fr,gb,gr,hr,ie,it,lt,lu,lv,mt,nl,pt,si,sk';}
document.getElementById('activateForm').onsubmit=async e=>{e.preventDefault();const fd=new FormData(e.target);fd.set('bot_mode',document.getElementById('botModeCheck').checked?'true':'false');fd.set('country_mode',document.getElementById('countryModeCheck').checked?'true':'false');fd.set('monitor_only',document.getElementById('monitorOnlyCheck').checked?'true':'false');await fetch('/api/shops/activate',{method:'POST',body:fd});closeModal('activateModal');};
async function deactivateShop(d){if(!confirm(d+' deaktivieren?'))return;const fd=new FormData();fd.append('domain',d);await fetch('/api/shops/deactivate',{method:'POST',body:fd});}
document.getElementById('activateForm').onsubmit=async e=>{e.preventDefault();const fd=new FormData(e.target);fd.set('bot_mode',document.getElementById('botModeCheck').checked?'true':'false');fd.set('country_mode',document.getElementById('countryModeCheck').checked?'true':'false');fd.set('monitor_only',document.getElementById('monitorOnlyCheck').checked?'true':'false');fd.set('restart_fpm',document.getElementById('autoFpmRestart').checked?'true':'false');await fetch('/api/shops/activate',{method:'POST',body:fd});closeModal('activateModal');};
async function deactivateShop(d){if(!confirm(d+' deaktivieren?'))return;const fd=new FormData();fd.append('domain',d);fd.append('restart_fpm',document.getElementById('autoFpmRestart').checked?'true':'false');await fetch('/api/shops/deactivate',{method:'POST',body:fd});}
function openBulkActivateModal(){document.getElementById('bulkMonitorOnlyCheck').checked=false;document.getElementById('bulkBotModeCheck').checked=true;document.getElementById('bulkCountryModeCheck').checked=false;toggleBulkMonitorOnly();toggleBulkBotOptions();toggleBulkCountryOptions();document.getElementById('bulkActivateModal').classList.add('open');}
function openBulkDeactivateModal(){document.getElementById('bulkDeactivateModal').classList.add('open');}
function toggleBulkMonitorOnly(){const isMonitor=document.getElementById('bulkMonitorOnlyCheck').checked;document.getElementById('bulkBlockingOptions').style.display=isMonitor?'none':'block';}
function toggleBulkBotOptions(){const isBot=document.getElementById('bulkBotModeCheck').checked;document.getElementById('bulkBotOptionsGroup').style.display=isBot?'block':'none';}
function toggleBulkCountryOptions(){const isCountry=document.getElementById('bulkCountryModeCheck').checked;document.getElementById('bulkCountryOptionsGroup').style.display=isCountry?'block':'none';}
function setBulkCountries(preset){const input=document.querySelector('#bulkActivateForm input[name="unlimited_countries"]');if(preset==='dach')input.value='de,at,ch';else if(preset==='eu_plus')input.value='de,at,ch,be,cy,ee,es,fi,fr,gb,gr,hr,ie,it,lt,lu,lv,mt,nl,pt,si,sk';}
document.getElementById('bulkActivateForm').onsubmit=async e=>{e.preventDefault();if(!confirm('Shops aktivieren?'))return;const fd=new FormData(e.target);fd.set('bot_mode',document.getElementById('bulkBotModeCheck').checked?'true':'false');fd.set('country_mode',document.getElementById('bulkCountryModeCheck').checked?'true':'false');fd.set('monitor_only',document.getElementById('bulkMonitorOnlyCheck').checked?'true':'false');closeModal('bulkActivateModal');toast('Aktivierung...','info');const r=await fetch('/api/shops/bulk-activate',{method:'POST',body:fd});const d=await r.json();if(d.success)toast(d.activated+' aktiviert','success');};
document.getElementById('bulkDeactivateForm').onsubmit=async e=>{e.preventDefault();if(!confirm('Shops deaktivieren?'))return;closeModal('bulkDeactivateModal');toast('Deaktivierung...','info');const r=await fetch('/api/shops/bulk-deactivate',{method:'POST',body:new FormData(e.target)});const d=await r.json();if(d.success)toast(d.deactivated+' deaktiviert','success');};
document.getElementById('bulkActivateForm').onsubmit=async e=>{e.preventDefault();if(!confirm('Shops aktivieren?'))return;const fd=new FormData(e.target);fd.set('bot_mode',document.getElementById('bulkBotModeCheck').checked?'true':'false');fd.set('country_mode',document.getElementById('bulkCountryModeCheck').checked?'true':'false');fd.set('monitor_only',document.getElementById('bulkMonitorOnlyCheck').checked?'true':'false');fd.set('restart_fpm',document.getElementById('autoFpmRestart').checked?'true':'false');closeModal('bulkActivateModal');toast('Aktivierung...','info');const r=await fetch('/api/shops/bulk-activate',{method:'POST',body:fd});const d=await r.json();if(d.success)toast(d.activated+' aktiviert','success');};
document.getElementById('bulkDeactivateForm').onsubmit=async e=>{e.preventDefault();if(!confirm('Shops deaktivieren?'))return;const fd=new FormData(e.target);fd.set('restart_fpm',document.getElementById('autoFpmRestart').checked?'true':'false');closeModal('bulkDeactivateModal');toast('Deaktivierung...','info');const r=await fetch('/api/shops/bulk-deactivate',{method:'POST',body:fd});const d=await r.json();if(d.success)toast(d.deactivated+' deaktiviert','success');};
function openPasswordModal(){document.getElementById('passwordModal').classList.add('open');}
document.getElementById('passwordForm').onsubmit=async e=>{e.preventDefault();const r=await fetch('/api/change-password',{method:'POST',body:new FormData(e.target)});const d=await r.json();if(d.success){toast('Passwort geändert','success');closeModal('passwordModal');e.target.reset();}else toast(d.error,'error');};
function openAllShopsModal(){document.getElementById('allShopsModal').classList.add('open');sortAllShops('req_per_min');}
@@ -1459,10 +1485,10 @@ def get_dashboard_html() -> str:
function formatTime(iso){return new Date(iso).toLocaleTimeString('de-DE');}
function formatRuntime(m){if(!m||m<=0)return'-';if(m<60)return Math.round(m)+'m';const h=m/60;if(h<24)return Math.round(h)+'h';return Math.round(h/24)+'d';}
function toast(msg,type='info'){const c=document.getElementById('toastContainer'),t=document.createElement('div');t.className='toast '+type;t.innerHTML='<span>'+msg+'</span>';c.appendChild(t);setTimeout(()=>t.remove(),4000);}
async function detailDeactivate(){if(!currentDetailShop)return;if(!confirm('Shop '+currentDetailShop+' deaktivieren?'))return;const fd=new FormData();fd.append('domain',currentDetailShop);toast('Deaktiviere...','info');await fetch('/api/shops/deactivate',{method:'POST',body:fd});closeModal('detailModal');}
async function detailDeactivate(){if(!currentDetailShop)return;if(!confirm('Shop '+currentDetailShop+' deaktivieren?'))return;const fd=new FormData();fd.append('domain',currentDetailShop);fd.append('restart_fpm',document.getElementById('autoFpmRestart').checked?'true':'false');toast('Deaktiviere...','info');await fetch('/api/shops/deactivate',{method:'POST',body:fd});closeModal('detailModal');}
function toggleRateLimitForm(){const area=document.getElementById('rateLimitFormArea');area.style.display=area.style.display==='none'?'block':'none';}
async function applyRateLimit(){if(!currentDetailShop)return;const rateLimit=document.getElementById('detailRateLimitInput').value;const banDuration=document.getElementById('detailBanDurationInput').value;if(!confirm('Rate-Limit aktivieren: '+rateLimit+' Req/min?'))return;const s=shops[currentDetailShop];toast('Wechsle zu Rate-Limit...','info');if(s&&s.status==='active'){const dfd=new FormData();dfd.append('domain',currentDetailShop);await fetch('/api/shops/deactivate',{method:'POST',body:dfd});await new Promise(r=>setTimeout(r,500));}const fd=new FormData();fd.append('domain',currentDetailShop);fd.append('bot_mode','true');fd.append('bot_rate_limit',rateLimit);fd.append('bot_ban_duration',banDuration);fd.append('country_mode','false');fd.append('monitor_only','false');await fetch('/api/shops/activate',{method:'POST',body:fd});closeModal('detailModal');}
async function detailSwitchMode(mode){if(!currentDetailShop)return;const s=shops[currentDetailShop];const modeNames={'bot-monitor':'🔍 Monitor','country-dach':'🇩🇪 DACH','country-eu':'🇪🇺 EU+'};if(!confirm('Modus wechseln zu '+modeNames[mode]+'?'))return;toast('Wechsle Modus...','info');if(s&&s.status==='active'){const dfd=new FormData();dfd.append('domain',currentDetailShop);await fetch('/api/shops/deactivate',{method:'POST',body:dfd});await new Promise(r=>setTimeout(r,500));}const fd=new FormData();fd.append('domain',currentDetailShop);if(mode==='bot-monitor'){fd.append('monitor_only','true');}else if(mode==='country-dach'){fd.append('bot_mode','true');fd.append('bot_rate_limit','30');fd.append('bot_ban_duration','300');fd.append('country_mode','true');fd.append('country_rate_limit','100');fd.append('country_ban_duration','600');fd.append('unlimited_countries','de,at,ch');}else if(mode==='country-eu'){fd.append('bot_mode','true');fd.append('bot_rate_limit','30');fd.append('bot_ban_duration','300');fd.append('country_mode','true');fd.append('country_rate_limit','100');fd.append('country_ban_duration','600');fd.append('unlimited_countries','de,at,ch,be,cy,ee,es,fi,fr,gb,gr,hr,ie,it,lt,lu,lv,mt,nl,pt,si,sk');}await fetch('/api/shops/activate',{method:'POST',body:fd});closeModal('detailModal');}
async function applyRateLimit(){if(!currentDetailShop)return;const rateLimit=document.getElementById('detailRateLimitInput').value;const banDuration=document.getElementById('detailBanDurationInput').value;const restartFpm=document.getElementById('autoFpmRestart').checked?'true':'false';if(!confirm('Rate-Limit aktivieren: '+rateLimit+' Req/min?'))return;const s=shops[currentDetailShop];toast('Wechsle zu Rate-Limit...','info');if(s&&s.status==='active'){const dfd=new FormData();dfd.append('domain',currentDetailShop);dfd.append('restart_fpm',restartFpm);await fetch('/api/shops/deactivate',{method:'POST',body:dfd});await new Promise(r=>setTimeout(r,500));}const fd=new FormData();fd.append('domain',currentDetailShop);fd.append('bot_mode','true');fd.append('bot_rate_limit',rateLimit);fd.append('bot_ban_duration',banDuration);fd.append('country_mode','false');fd.append('monitor_only','false');fd.append('restart_fpm',restartFpm);await fetch('/api/shops/activate',{method:'POST',body:fd});closeModal('detailModal');}
async function detailSwitchMode(mode){if(!currentDetailShop)return;const s=shops[currentDetailShop];const restartFpm=document.getElementById('autoFpmRestart').checked?'true':'false';const modeNames={'bot-monitor':'🔍 Monitor','country-dach':'🇩🇪 DACH','country-eu':'🇪🇺 EU+'};if(!confirm('Modus wechseln zu '+modeNames[mode]+'?'))return;toast('Wechsle Modus...','info');if(s&&s.status==='active'){const dfd=new FormData();dfd.append('domain',currentDetailShop);dfd.append('restart_fpm',restartFpm);await fetch('/api/shops/deactivate',{method:'POST',body:dfd});await new Promise(r=>setTimeout(r,500));}const fd=new FormData();fd.append('domain',currentDetailShop);fd.append('restart_fpm',restartFpm);if(mode==='bot-monitor'){fd.append('monitor_only','true');}else if(mode==='country-dach'){fd.append('bot_mode','true');fd.append('bot_rate_limit','30');fd.append('bot_ban_duration','300');fd.append('country_mode','true');fd.append('country_rate_limit','100');fd.append('country_ban_duration','600');fd.append('unlimited_countries','de,at,ch');}else if(mode==='country-eu'){fd.append('bot_mode','true');fd.append('bot_rate_limit','30');fd.append('bot_ban_duration','300');fd.append('country_mode','true');fd.append('country_rate_limit','100');fd.append('country_ban_duration','600');fd.append('unlimited_countries','de,at,ch,be,cy,ee,es,fi,fr,gb,gr,hr,ie,it,lt,lu,lv,mt,nl,pt,si,sk');}await fetch('/api/shops/activate',{method:'POST',body:fd});closeModal('detailModal');}
connect();
setUpdateInterval(10000);
</script>