diff --git a/assets/js/wd-core.js b/assets/js/wd-core.js
index d720d54f..8338d20b 100644
--- a/assets/js/wd-core.js
+++ b/assets/js/wd-core.js
@@ -863,7 +863,7 @@
Stand haben. Die Nummer wird zusammen mit CACHE_NAME in sw.js
hochgezaehlt -- beide gehoeren zusammen. */
navigator.serviceWorker
- .register("/webdesign/sw.js?v=60", { scope: "/webdesign/" })
+ .register("/webdesign/sw.js?v=61", { scope: "/webdesign/" })
.catch(function () { /* still schlucken: ohne SW funktioniert alles weiter */ });
});
}
diff --git a/webdesign/sw.js b/webdesign/sw.js
index c6b943c5..24c12d7a 100644
--- a/webdesign/sw.js
+++ b/webdesign/sw.js
@@ -34,7 +34,7 @@
Start alle alten Zwischenspeicher weg. Muss bei jeder Änderung an den
Dateien unten hochgezählt werden, sonst hängen Nutzer auf einem alten
Stand fest. */
-const CACHE_NAME = "dogfather-webdesign-v60";
+const CACHE_NAME = "dogfather-webdesign-v61";
/* Bausteine, die die Oberfläche zum Anzeigen braucht. Bewusst KEINE
HTML-Datei in dieser Liste. */
diff --git a/webdesign/verwaltung.html b/webdesign/verwaltung.html
index 26fbe001..c65bdbf5 100644
--- a/webdesign/verwaltung.html
+++ b/webdesign/verwaltung.html
@@ -2275,6 +2275,43 @@
Bestehende Zugänge
Wird geladen…
+
+
+
+
+ Auskunft und Löschung (DSGVO)
+
+
+
+ Für Anfragen nach Art. 15 („Welche Daten haben Sie über mich?“)
+ und Art. 17 („Bitte löschen Sie meine Daten“). Beides ist
+ binnen eines Monats zu beantworten.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2966,6 +3003,162 @@
return browser + (system ? " auf " + system : "");
}
+ /* =====================================================================
+ AUSKUNFT UND LÖSCHUNG (DSGVO Art. 15/17)
+
+ Drei Schritte, und die Reihenfolge ist Absicht: sehen, Vorschau,
+ erst dann ausführen. Eine Löschung ist endgültig — sie gehört nicht
+ hinter einen Knopf, der sofort zuschlägt.
+
+ Die Auskunft wird als Datei zum Herunterladen angeboten, nicht nur
+ angezeigt. Man muss sie der Person schicken können, und zwar
+ vollständig; abtippen wäre der sicherste Weg, etwas zu vergessen.
+ ===================================================================== */
+ function dsMail() {
+ var f = document.getElementById("vw-ds-mail");
+ return f ? f.value.trim() : "";
+ }
+
+ function dsMeldung(html, art) {
+ var z = document.getElementById("vw-ds-ergebnis");
+ if (!z) return;
+ var farbe = art === "warn" ? "var(--wd-lila-hell)"
+ : art === "gut" ? "var(--wd-aqua)" : "var(--wd-rand)";
+ z.innerHTML = '
' + html + '
';
+ }
+
+ async function dsAuskunft() {
+ var mail = dsMail();
+ if (!mail) return dsMeldung("Bitte zuerst eine E-Mail-Adresse eintragen.", "warn");
+ dsMeldung("Wird zusammengetragen…");
+
+ var d;
+ try {
+ d = await api("/webdesign/admin/datenschutz/auskunft", { method: "POST", body: { email: mail } });
+ } catch (fehler) {
+ return dsMeldung("Nicht möglich: " + s((fehler && fehler.message) || "unbekannter Fehler") +
+ (fehler && fehler.status === 404
+ ? ' Der Server kennt diesen Zugang noch nicht — er braucht einen Neustart mit dem neuen Stand.'
+ : ""), "warn");
+ }
+ if (!d || !d.ok) return dsMeldung("Nicht möglich: " + s((d && d.error) || "unbekannt"), "warn");
+
+ if (!d.datensaetze) {
+ return dsMeldung("Zu " + s(mail) + " ist nichts gespeichert.", "gut");
+ }
+
+ var liste = (d.bereiche || []).map(function (b) {
+ return "
", "gut");
+
+ var knopf = document.getElementById("vw-ds-laden");
+ if (knopf) {
+ knopf.addEventListener("click", function () {
+ /* Die vollständige Auskunft, wie sie herausgegeben wird. JSON,
+ weil Art. 20 ein "gängiges, maschinenlesbares Format"
+ verlangt — und weil nichts verloren geht. */
+ var blob = new Blob([JSON.stringify(d, null, 2)], { type: "application/json" });
+ var url = URL.createObjectURL(blob);
+ var a = document.createElement("a");
+ a.href = url;
+ a.download = "auskunft-" + mail.replace(/[^a-z0-9]/gi, "-") + "-" +
+ new Date().toISOString().slice(0, 10) + ".json";
+ a.click();
+ URL.revokeObjectURL(url);
+ });
+ }
+ }
+
+ async function dsVorschau() {
+ var mail = dsMail();
+ if (!mail) return dsMeldung("Bitte zuerst eine E-Mail-Adresse eintragen.", "warn");
+ dsMeldung("Wird geprüft…");
+
+ var d;
+ try {
+ d = await api("/webdesign/admin/datenschutz/vorschau", { method: "POST", body: { email: mail } });
+ } catch (fehler) {
+ return dsMeldung("Nicht möglich: " + s((fehler && fehler.message) || "unbekannt"), "warn");
+ }
+ if (!d || !d.ok) return dsMeldung("Nicht möglich: " + s((d && d.error) || "unbekannt"), "warn");
+
+ var weg = (d.loeschbar || []).map(function (x) {
+ return "
" + s(String(x.anzahl)) + "× " + s(x.was) + "
";
+ }).join("") || '
nichts
';
+
+ /* Der wichtigere Teil: was NICHT gelöscht werden darf, mit Grund
+ und Datum. Ohne diese Angabe müsste man bei jeder Anfrage neu
+ nachschlagen, welche Frist gilt. */
+ var bleibt = (d.bleibt || []).map(function (x) {
+ return "
"
+ : ""), "warn");
+
+ var lk = document.getElementById("vw-ds-loeschen");
+ if (lk) lk.addEventListener("click", dsLoeschen);
+ }
+
+ async function dsLoeschen() {
+ var mail = dsMail();
+ var best = document.getElementById("vw-ds-best");
+ var bestaetigung = best ? best.value.trim() : "";
+
+ if (mail.toLowerCase() !== bestaetigung.toLowerCase()) {
+ return dsMeldung("Die beiden Adressen stimmen nicht überein. " +
+ "Zum Schutz vor einem Vertipper wird sie ein zweites Mal verlangt — " +
+ "der Unterschied zwischen .de und .com ist ein Buchstabe, die Folge unwiederbringlich.", "warn");
+ }
+
+ dsMeldung("Wird gelöscht…");
+ var d;
+ try {
+ d = await api("/webdesign/admin/datenschutz/loeschen",
+ { method: "POST", body: { email: mail, bestaetigung: bestaetigung } });
+ } catch (fehler) {
+ return dsMeldung("Nicht möglich: " + s((fehler && fehler.message) || "unbekannt"), "warn");
+ }
+ if (!d || !d.ok) return dsMeldung("Nicht möglich: " + s((d && d.error) || "unbekannt"), "warn");
+
+ dsMeldung("" + s(String(d.geloescht)) + " Datensätze gelöscht." +
+ '
' + s(d.hinweis || "") + "
", "gut");
+ }
+
+ (function dsVerdrahten() {
+ var a = document.getElementById("vw-ds-auskunft");
+ if (a) a.addEventListener("click", dsAuskunft);
+ var v = document.getElementById("vw-ds-vorschau");
+ if (v) v.addEventListener("click", dsVorschau);
+ })();
+
async function ladeUebersicht() {
var laedt = document.getElementById("vw-ub-laedt");
var inhalt = document.getElementById("vw-ub-inhalt");