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();
+ });
});
}