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 "
  • " + s(String(b.anzahl)) + "× " + s(b.was) + + (b.aufbewahren ? ' (aufbewahrungspflichtig)' : "") + + "
  • "; + }).join(""); + + dsMeldung( + "" + s(String(d.datensaetze)) + " Datensätze zu " + s(mail) + + '" + + '
    ' + + '
    ", "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 "
  • " + s(String(x.anzahl)) + "× " + s(x.was) + + '
    ' + s(x.grund) + + " · frei ab " + s(x.freiAb) + "
  • "; + }).join(""); + + dsMeldung( + "Würde gelöscht" + + '" + + (bleibt + ? "Bleibt (gesetzliche Aufbewahrung)" + + '" + : "") + + '

    ' + s(d.hinweis || "") + "

    " + + ((d.loeschbar || []).length + ? '
    ' + + '' + + '' + + "
    " + + '
    ' + + '
    " + : ""), "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");