File size: 2,410 Bytes
889e86b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
da1822e
 
 
 
 
 
 
889e86b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
"""
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}