From 7352438b11b0a5c9bada4bb8ed8168f2222edfa3 Mon Sep 17 00:00:00 2001 From: Meleki Date: Fri, 13 Mar 2026 15:58:31 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20Scanned-Keys=20'Alle=20pr=C3=BCfen'=20B?= =?UTF-8?q?utton=20+=20EasyMDE=20Refresh=20nach=20More-Toggle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - POST /api/admin/api-keys/scanned/recheck-all: prüft alle nicht-adoptierten Scanned-Keys sequenziell - Button mit Loading-State, Ergebnis-Toast und Auto-Reload - EasyMDE/CodeMirror refresh() nach initMoreButton() Einblenden (behebt leeren Editor-Bug) --- Endpoints/ApiKeysEndpoint.cs | 22 ++++++++++++++++++++++ wwwroot/index.html | 1 + wwwroot/js/api.js | 1 + wwwroot/js/pages/api-keys-page.js | 16 ++++++++++++++++ wwwroot/js/ui-helpers.js | 8 +++++++- 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Endpoints/ApiKeysEndpoint.cs b/Endpoints/ApiKeysEndpoint.cs index 855d293..a67b5fb 100644 --- a/Endpoints/ApiKeysEndpoint.cs +++ b/Endpoints/ApiKeysEndpoint.cs @@ -29,6 +29,7 @@ public static class ApiKeysEndpoint app.MapPost("/api/admin/api-keys/scan", HandleScanTrigger); app.MapGet("/api/admin/api-keys/scan/status", HandleScanStatus); app.MapGet("/api/admin/api-keys/scanned", HandleGetScanned); + app.MapPost("/api/admin/api-keys/scanned/recheck-all", HandleRecheckAll); app.MapPost("/api/admin/api-keys/scanned/{id}/recheck", HandleRecheck); app.MapPost("/api/admin/api-keys/scanned/{id}/adopt", HandleAdopt); app.MapDelete("/api/admin/api-keys/scanned/{id}", HandleDeleteScanned); @@ -274,6 +275,27 @@ public static class ApiKeysEndpoint await ctx.Response.WriteAsJsonAsync(result); } + private static async Task HandleRecheckAll(HttpContext ctx, DatabaseService db, KeyScannerService scanner) + { + if (!ctx.IsAdmin()) { ctx.Response.StatusCode = 403; return; } + + var keys = await db.GetScannedKeys(); + var notAdopted = keys.Where(k => k.AdoptedApiKeyId == null).ToList(); + + int success = 0, errors = 0; + foreach (var sk in notAdopted) + { + try + { + await scanner.CheckAndUpdateKey(sk); + success++; + } + catch { errors++; } + } + + await ctx.Response.WriteAsJsonAsync(new { ok = true, total = notAdopted.Count, success, errors }); + } + private static async Task HandleRecheck(HttpContext ctx, DatabaseService db, KeyScannerService scanner, string id) { if (!ctx.IsAdmin()) { ctx.Response.StatusCode = 403; return; } diff --git a/wwwroot/index.html b/wwwroot/index.html index 498d926..b66cbb6 100644 --- a/wwwroot/index.html +++ b/wwwroot/index.html @@ -585,6 +585,7 @@

Key Scanner

+ diff --git a/wwwroot/js/api.js b/wwwroot/js/api.js index c12e9a7..0e99a4d 100644 --- a/wwwroot/js/api.js +++ b/wwwroot/js/api.js @@ -235,6 +235,7 @@ function apiCheckAllApiKeys() { return _post('/api/admin/api-keys/check-all', un function apiTriggerScan(mode) { return _post('/api/admin/api-keys/scan?mode=' + (mode || 'full'), undefined, 'Fehler beim Starten des Scans'); } function apiScanStatus() { return _get('/api/admin/api-keys/scan/status', {}); } function apiGetScannedKeys() { return _get('/api/admin/api-keys/scanned', []); } +function apiRecheckAllScannedKeys() { return _post('/api/admin/api-keys/scanned/recheck-all', undefined, 'Fehler beim Prüfen'); } function apiRecheckScannedKey(id) { return _post('/api/admin/api-keys/scanned/' + id + '/recheck', undefined, 'Fehler beim Prüfen'); } function apiAdoptScannedKey(id) { return _post('/api/admin/api-keys/scanned/' + id + '/adopt', undefined, 'Fehler beim Übernehmen'); } function apiDeleteScannedKey(id) { return _del('/api/admin/api-keys/scanned/' + id, 'Fehler beim Löschen'); } diff --git a/wwwroot/js/pages/api-keys-page.js b/wwwroot/js/pages/api-keys-page.js index f378087..ceec24f 100644 --- a/wwwroot/js/pages/api-keys-page.js +++ b/wwwroot/js/pages/api-keys-page.js @@ -318,6 +318,7 @@ registerPage('api-keys', { var scanQuickBtn = document.getElementById('scanQuickBtn'); var scanWebBtn = document.getElementById('scanWebBtn'); var scanFullBtn = document.getElementById('scanFullBtn'); + var recheckAllScannedBtn = document.getElementById('recheckAllScannedBtn'); var scanBtns = [scanQuickBtn, scanWebBtn, scanFullBtn]; var scanStatusEl = document.getElementById('scanStatus'); var scannedList = document.getElementById('scannedKeysList'); @@ -497,6 +498,21 @@ registerPage('api-keys', { scanWebBtn.addEventListener('click', function() { triggerScan('web', scanWebBtn); }); scanFullBtn.addEventListener('click', function() { triggerScan('full', scanFullBtn); }); + recheckAllScannedBtn.addEventListener('click', async function() { + recheckAllScannedBtn.disabled = true; + recheckAllScannedBtn.innerHTML = ' Prüfe…'; + try { + var result = await apiRecheckAllScannedKeys(); + showToast('Alle geprüft: ' + result.success + '/' + result.total + ' OK' + (result.errors > 0 ? ', ' + result.errors + ' Fehler' : ''), result.errors > 0 ? 'warning' : 'success'); + await loadScannedKeys(); + } catch(e) { + showToast('Fehler beim Prüfen', 'error'); + } finally { + recheckAllScannedBtn.disabled = false; + recheckAllScannedBtn.innerHTML = ' Alle prüfen'; + } + }); + await loadScannedKeys(); await updateScanStatus(); }, diff --git a/wwwroot/js/ui-helpers.js b/wwwroot/js/ui-helpers.js index c57e8df..1d49dbe 100644 --- a/wwwroot/js/ui-helpers.js +++ b/wwwroot/js/ui-helpers.js @@ -134,8 +134,14 @@ function initMoreButton(moreEl) { if (!moreEl) return; moreEl.addEventListener('click', () => { const content = moreEl.querySelector('[hidden]'); - while (content.firstChild) moreEl.parentNode.insertBefore(content.firstChild, moreEl); + const parent = moreEl.parentNode; + while (content.firstChild) parent.insertBefore(content.firstChild, moreEl); moreEl.remove(); + // EasyMDE/CodeMirror braucht refresh() nach Sichtbarwerden + parent.querySelectorAll('.EasyMDEContainer').forEach(c => { + const cm = c.querySelector('.CodeMirror'); + if (cm && cm.CodeMirror) cm.CodeMirror.refresh(); + }); }); }