""" Account-Löschung (DSGVO + App-Store-Gl. 4): muss FK-sicher ALLE Daten entfernen, auch wenn der User Zeilen in Tabellen ohne ON DELETE CASCADE hat (routes, places, walks, events, forum_threads, …). Regressionstest gegen den alten, FK-unvollständigen Delete, der am finalen `DELETE FROM users` scheiterte, sobald solche Zeilen existierten. """ import secrets def _make_user(client): from database import db email = f"del-{secrets.token_hex(4)}@example.com" pw, name = "TestPass123!", f"deltest{secrets.token_hex(3)}" r = client.post("/api/auth/register", json={"email": email, "password": pw, "name": name}) assert r.status_code == 200, r.text with db() as conn: conn.execute("UPDATE users SET email_verified=1 WHERE email=?", (email,)) uid = conn.execute("SELECT id FROM users WHERE email=?", (email,)).fetchone()["id"] token = client.post("/api/auth/login", json={"email": email, "password": pw}).json()["token"] return uid, {"Authorization": f"Bearer {token}"} def test_delete_account_with_noncascade_data(client): from database import db uid, headers = _make_user(client) dog_id = client.post("/api/dogs", headers=headers, json={"name": "Rex", "rasse": "Mix", "is_public": False}).json()["id"] # Direkt Zeilen in den Tabellen anlegen, die users(id) OHNE Cascade referenzieren — # genau die, die den alten Delete blockiert haben. with db() as conn: conn.execute("INSERT INTO routes (user_id, name, gps_track) VALUES (?,?,?)", (uid, "Testrunde", "[]")) conn.execute("INSERT INTO places (user_id, name, typ, lat, lon) VALUES (?,?,?,?,?)", (uid, "Hundewiese", "freilauf", 52.5, 13.4)) conn.execute("INSERT INTO walks (user_id, titel, datum, uhrzeit, lat, lon) VALUES (?,?,?,?,?,?)", (uid, "Gassi-Treff", "2026-07-01", "18:00", 52.5, 13.4)) conn.execute("INSERT INTO events (user_id, titel, datum) VALUES (?,?,?)", (uid, "Hundewanderung", "2026-07-02")) conn.execute("INSERT INTO forum_threads (user_id, titel) VALUES (?,?)", (uid, "Hallo Forum")) resp = client.delete("/api/profile/account", headers=headers) assert resp.status_code == 200, f"Delete failed: {resp.status_code} {resp.text}" assert resp.json()["status"] == "deleted" with db() as conn: assert conn.execute("SELECT 1 FROM users WHERE id=?", (uid,)).fetchone() is None for tbl in ("routes", "places", "walks", "events", "forum_threads", "dogs"): cnt = conn.execute(f"SELECT COUNT(*) c FROM {tbl} WHERE user_id=?", (uid,)).fetchone()["c"] assert cnt == 0, f"{tbl} hat noch {cnt} Zeile(n) nach Account-Löschung" def test_delete_account_minimal_user(client): """Auch ein User ganz ohne Zusatzdaten lässt sich löschen.""" from database import db uid, headers = _make_user(client) resp = client.delete("/api/profile/account", headers=headers) assert resp.status_code == 200, resp.text with db() as conn: assert conn.execute("SELECT 1 FROM users WHERE id=?", (uid,)).fetchone() is None