Files
at2-webapp-dicta2stream/account_router.py

137 lines
5.4 KiB
Python

# account_router.py — Account management endpoints
from fastapi import APIRouter, Request, HTTPException, Depends
from fastapi.responses import JSONResponse
from sqlmodel import Session, select
from models import User, UserQuota, UploadLog, DBSession, PublicStream
from database import get_db
import os
from typing import Dict, Any
router = APIRouter(prefix="/api", tags=["account"])
@router.post("/delete-account")
async def delete_account(data: Dict[str, Any], request: Request):
try:
# Get UID from request data
uid = data.get("uid")
if not uid:
# Debug messages disabled
raise HTTPException(status_code=400, detail="Missing UID")
ip = request.client.host
# Debug messages disabled
# Verify user exists and IP matches
# Use the database session context manager
with get_db() as db:
# Handle both email-based and username-based UIDs for backward compatibility
user = None
# First try to find by email (new UID format)
if '@' in uid:
user = db.query(User).filter(User.email == uid).first()
# Debug messages disabled
# If not found by email, try by username (legacy UID format)
if not user:
user = db.query(User).filter(User.username == uid).first()
# Debug messages disabled
if not user:
# Debug messages disabled
raise HTTPException(status_code=404, detail="User not found")
# Extract user attributes while the object is still bound to the session
actual_uid = user.email
user_ip = user.ip
username = user.username
# Debug messages disabled
if user_ip != ip:
# Debug messages disabled
raise HTTPException(status_code=403, detail="Unauthorized: IP address does not match")
# Use the database session context manager for all database operations
with get_db() as db:
try:
# Delete user's upload logs (use actual_uid which is always the email)
uploads = db.query(UploadLog).filter(UploadLog.uid == actual_uid).all()
for upload in uploads:
db.delete(upload)
# Debug messages disabled
# Delete user's public streams
streams = db.query(PublicStream).filter(PublicStream.uid == actual_uid).all()
for stream in streams:
db.delete(stream)
# Debug messages disabled
# Delete user's quota
quota = db.get(UserQuota, actual_uid)
if quota:
db.delete(quota)
# Debug messages disabled
# Delete user's active sessions (check both email and username as uid)
sessions_by_email = db.query(DBSession).filter(DBSession.uid == actual_uid).all()
sessions_by_username = db.query(DBSession).filter(DBSession.uid == username).all()
all_sessions = list(sessions_by_email) + list(sessions_by_username)
# Remove duplicates using token (primary key)
unique_sessions = {session.token: session for session in all_sessions}.values()
for session in unique_sessions:
db.delete(session)
# Debug messages disabled
# Delete user account
user_obj = db.get(User, actual_uid) # Use actual_uid which is the email
if user_obj:
db.delete(user_obj)
# Debug messages disabled
db.commit()
# Debug messages disabled
except Exception as e:
db.rollback()
# Debug messages disabled
# Debug messages disabled
raise HTTPException(status_code=500, detail="Database error during account deletion")
# Delete user's files
try:
# Use the email (actual_uid) for the directory name, which matches how files are stored
user_dir = os.path.join('data', actual_uid)
real_user_dir = os.path.realpath(user_dir)
# Security check to prevent directory traversal
if not real_user_dir.startswith(os.path.realpath('data')):
# Debug messages disabled
raise HTTPException(status_code=400, detail="Invalid user directory")
if os.path.exists(real_user_dir):
import shutil
shutil.rmtree(real_user_dir, ignore_errors=True)
# Debug messages disabled
else:
# Debug messages disabled
pass
except Exception as e:
# Debug messages disabled
# Continue even if file deletion fails, as the account is already deleted from the DB
pass
# Debug messages disabled
return {"status": "success", "message": "Account and all associated data have been deleted"}
except HTTPException as he:
# Debug messages disabled
raise
except Exception as e:
# Debug messages disabled
raise HTTPException(status_code=500, detail="An unexpected error occurred")