Feature: Konto löschen (Play Store Pflicht) — DELETE /profile/account + Button in Settings (SW by-v786)
This commit is contained in:
parent
e8cf742911
commit
e4b170d45b
6 changed files with 59 additions and 7 deletions
|
|
@ -327,7 +327,7 @@ MEDIA_DIR = os.getenv("MEDIA_DIR", "/data/media")
|
||||||
os.makedirs(MEDIA_DIR, exist_ok=True)
|
os.makedirs(MEDIA_DIR, exist_ok=True)
|
||||||
app.mount("/media", StaticFiles(directory=MEDIA_DIR), name="media")
|
app.mount("/media", StaticFiles(directory=MEDIA_DIR), name="media")
|
||||||
|
|
||||||
APP_VER = "785" # muss mit APP_VER in app.js übereinstimmen
|
APP_VER = "786" # muss mit APP_VER in app.js übereinstimmen
|
||||||
|
|
||||||
@app.get("/.well-known/assetlinks.json")
|
@app.get("/.well-known/assetlinks.json")
|
||||||
async def assetlinks():
|
async def assetlinks():
|
||||||
|
|
|
||||||
|
|
@ -142,3 +142,28 @@ async def put_world_config(body: WorldConfigIn, user=Depends(get_current_user)):
|
||||||
conn.execute("UPDATE users SET world_config=? WHERE id=?",
|
conn.execute("UPDATE users SET world_config=? WHERE id=?",
|
||||||
(_json.dumps(body.config), user['id']))
|
(_json.dumps(body.config), user['id']))
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------
|
||||||
|
# DELETE /profile/account — Konto unwiderruflich löschen
|
||||||
|
# ----------------------------------------------------------
|
||||||
|
@router.delete('/account')
|
||||||
|
async def delete_account(user=Depends(get_current_user)):
|
||||||
|
"""Löscht das Konto und alle zugehörigen Daten unwiderruflich."""
|
||||||
|
uid = user['id']
|
||||||
|
with db() as conn:
|
||||||
|
# Alle Hunde-IDs des Users
|
||||||
|
dog_ids = [r['id'] for r in conn.execute(
|
||||||
|
"SELECT id FROM dogs WHERE user_id=?", (uid,)).fetchall()]
|
||||||
|
for did in dog_ids:
|
||||||
|
conn.execute("DELETE FROM diary WHERE dog_id=?", (did,))
|
||||||
|
conn.execute("DELETE FROM health WHERE dog_id=?", (did,))
|
||||||
|
conn.execute("DELETE FROM training_sessions WHERE dog_id=?", (did,))
|
||||||
|
conn.execute("DELETE FROM training_streaks WHERE dog_id=?", (did,))
|
||||||
|
conn.execute("DELETE FROM expenses WHERE dog_id=?", (did,))
|
||||||
|
conn.execute("DELETE FROM dogs WHERE user_id=?", (uid,))
|
||||||
|
conn.execute("DELETE FROM push_subscriptions WHERE user_id=?", (uid,))
|
||||||
|
conn.execute("DELETE FROM notifications WHERE user_id=?", (uid,))
|
||||||
|
conn.execute("DELETE FROM forum_posts WHERE user_id=?", (uid,))
|
||||||
|
conn.execute("DELETE FROM users WHERE id=?", (uid,))
|
||||||
|
return {"status": "deleted"}
|
||||||
|
|
|
||||||
|
|
@ -575,10 +575,10 @@
|
||||||
<div id="modal-container"></div>
|
<div id="modal-container"></div>
|
||||||
|
|
||||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||||
<script src="/js/api.js?v=785"></script>
|
<script src="/js/api.js?v=786"></script>
|
||||||
<script src="/js/ui.js?v=785"></script>
|
<script src="/js/ui.js?v=786"></script>
|
||||||
<script src="/js/app.js?v=785"></script>
|
<script src="/js/app.js?v=786"></script>
|
||||||
<script src="/js/worlds.js?v=785"></script>
|
<script src="/js/worlds.js?v=786"></script>
|
||||||
|
|
||||||
<!-- Feature-Seiten werden lazy geladen -->
|
<!-- Feature-Seiten werden lazy geladen -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Router, State-Management, Navigation, Initialisierung.
|
Router, State-Management, Navigation, Initialisierung.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const APP_VER = '785'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
const APP_VER = '786'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||||
const APP_VERSION = '1.5.0'; // ← semantische Version, wird bei make release gesetzt
|
const APP_VERSION = '1.5.0'; // ← semantische Version, wird bei make release gesetzt
|
||||||
const IS_STAGING = location.hostname === 'staging.banyaro.app';
|
const IS_STAGING = location.hostname === 'staging.banyaro.app';
|
||||||
// Cache-Bust-Parameter nach Update-Reload sofort entfernen
|
// Cache-Bust-Parameter nach Update-Reload sofort entfernen
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,15 @@ window.Page_settings = (() => {
|
||||||
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#sign-out"></use></svg>
|
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#sign-out"></use></svg>
|
||||||
Abmelden
|
Abmelden
|
||||||
</button>
|
</button>
|
||||||
|
<button id="settings-delete-account-btn"
|
||||||
|
style="width:100%;margin-top:var(--space-2);display:flex;align-items:center;justify-content:center;
|
||||||
|
gap:var(--space-2);padding:var(--space-2) var(--space-4);
|
||||||
|
border-radius:var(--radius-md);border:none;
|
||||||
|
background:none;color:var(--c-text-muted);
|
||||||
|
font-size:var(--text-xs);cursor:pointer">
|
||||||
|
<svg class="ph-icon" aria-hidden="true" style="width:12px;height:12px"><use href="/icons/phosphor.svg#trash"></use></svg>
|
||||||
|
Konto löschen
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -789,6 +798,24 @@ window.Page_settings = (() => {
|
||||||
_render();
|
_render();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('settings-delete-account-btn')?.addEventListener('click', async () => {
|
||||||
|
const ok = await UI.modal.confirm({
|
||||||
|
title: 'Konto unwiderruflich löschen?',
|
||||||
|
body: 'Alle deine Daten (Tagebuch, Gesundheit, Training, Fotos) werden dauerhaft gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.',
|
||||||
|
confirmText: 'Ja, Konto löschen',
|
||||||
|
danger: true,
|
||||||
|
});
|
||||||
|
if (!ok) return;
|
||||||
|
try {
|
||||||
|
await API.del('/profile/account');
|
||||||
|
_appState.user = null; _appState.dogs = []; _appState.activeDog = null;
|
||||||
|
UI.toast.info('Dein Konto wurde gelöscht.');
|
||||||
|
App.navigate('welcome');
|
||||||
|
} catch {
|
||||||
|
UI.toast.error('Konto konnte nicht gelöscht werden. Bitte versuche es erneut.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById('settings-install-btn')?.addEventListener('click', () => {
|
document.getElementById('settings-install-btn')?.addEventListener('click', () => {
|
||||||
App.navigate('welcome', true, { install: true });
|
App.navigate('welcome', true, { install: true });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Offline-Cache + Push Notifications + Tile-Cache
|
Offline-Cache + Push Notifications + Tile-Cache
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const CACHE_VERSION = 'by-v785';
|
const CACHE_VERSION = 'by-v786';
|
||||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||||
const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache
|
const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue