venthrive-api / routes /account.py
GitHub Actions
Sync from GitHub · 2026-10-13 07:41 UTC
da1822e
Raw History Blame Contribute Delete
2.41 kB
"""
Account Routes — self-service actions on the caller's own account.
Unlike routes/admin.py, these never take a target uid from the request — the
uid always comes from the verified Firebase ID token, so a user can only ever
act on their own account.
"""
from fastapi import APIRouter, Depends, HTTPException
from firebase_admin import auth as fb_auth, firestore
from auth import verify_firebase_token
router = APIRouter()
def delete_all_user_data(uid: str) -> None:
"""
Deletes every Firestore document owned by a user: each business's
subcollections, the business docs themselves, xpHistory, and the
user_data root doc. Shared by this self-delete route and
routes/admin.py's delete_user so the cascade is defined once.
"""
db = firestore.client()
user_ref = db.collection("user_data").document(uid)
for biz in user_ref.collection("businesses").stream():
for sub in ["bff", "profile_output", "documents", "kanban", "milestones", "sessions", "team"]:
for sdoc in biz.reference.collection(sub).stream():
sdoc.reference.delete()
biz.reference.delete()
for entry in user_ref.collection("xpHistory").stream():
entry.reference.delete()
user_ref.delete()
# Data keyed to the uid outside user_data: rate-limit violation logs and any
# consultant booking records.
for entry in db.collection("rate_limit_violations").where("uid", "==", uid).stream():
entry.reference.delete()
for booking in db.collection_group("bookings").where("userId", "==", uid).stream():
booking.reference.delete()
@router.delete("/me")
def delete_own_account(user: dict = Depends(verify_firebase_token)):
"""
Deletes the caller's own account: all Firestore data (via the Admin SDK,
which bypasses firestore.rules — user_data deletion is deliberately
backend-only, see firestore.rules' own comment) and the Firebase Auth
user record. The frontend re-authenticates the user with their password
immediately before calling this, as an extra confirmation step.
"""
uid = user.get("uid")
if not uid:
raise HTTPException(status_code=401, detail="Unauthorized.")
delete_all_user_data(uid)
try:
fb_auth.delete_user(uid)
except fb_auth.UserNotFoundError:
pass # already gone — not an error for a delete
return {"success": True}