Improve user delete flow

This commit is contained in:
Urtzi Alfaro
2025-08-02 17:09:53 +02:00
parent 277e8bec73
commit 3681429e11
10 changed files with 1334 additions and 210 deletions

View File

@@ -7,6 +7,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from typing import Dict, Any
import structlog
import uuid
from datetime import datetime, timezone
from app.core.database import get_db
from app.schemas.auth import UserResponse, PasswordChange
@@ -120,7 +121,7 @@ async def update_current_user(
detail="Failed to update user"
)
@router.delete("/delete/users/{user_id}")
@router.delete("/delete/{user_id}")
async def delete_admin_user(
user_id: str,
background_tasks: BackgroundTasks,
@@ -158,35 +159,83 @@ async def delete_admin_user(
detail="Cannot delete your own account"
)
# Initialize deletion service
# Quick validation that user exists before starting background task
deletion_service = AdminUserDeleteService(db)
# Perform the deletion
try:
result = await deletion_service.delete_admin_user_complete(
user_id=user_id,
requesting_user_id=current_user.id
)
return {
"success": True,
"message": f"Admin user {user_id} has been successfully deleted",
"deletion_details": result
}
except HTTPException:
raise
except Exception as e:
logger.error("Unexpected error during user deletion",
user_id=user_id,
error=str(e))
user_info = await deletion_service._validate_admin_user(user_id)
if not user_info:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An unexpected error occurred during user deletion"
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Admin user {user_id} not found"
)
# Start deletion as background task for better performance
background_tasks.add_task(
execute_admin_user_deletion,
user_id=user_id,
requesting_user_id=current_user.id,
db_url=str(db.bind.url) # Pass DB connection string for background task
)
return {
"success": True,
"message": f"Admin user deletion for {user_id} has been initiated",
"status": "processing",
"user_info": user_info,
"initiated_at": datetime.utcnow().isoformat(),
"note": "Deletion is processing in the background. Check logs for completion status."
}
# Add this background task function to services/auth/app/api/users.py:
async def execute_admin_user_deletion(
user_id: str,
requesting_user_id: str,
db_url: str
):
"""
Background task to execute complete admin user deletion
"""
# Create new database session for background task
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
engine = create_async_engine(db_url)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async with async_session() as session:
try:
# Initialize deletion service with new session
deletion_service = AdminUserDeleteService(session)
# Perform the deletion
result = await deletion_service.delete_admin_user_complete(
user_id=user_id,
requesting_user_id=requesting_user_id
)
logger.info("Background admin user deletion completed successfully",
user_id=user_id,
requesting_user=requesting_user_id,
result=result)
except Exception as e:
logger.error("Background admin user deletion failed",
user_id=user_id,
requesting_user=requesting_user_id,
error=str(e))
# Attempt to publish failure event
try:
deletion_service = AdminUserDeleteService(session)
await deletion_service._publish_user_deletion_failed_event(user_id, str(e))
except:
pass
finally:
await engine.dispose()
@router.get("/delete/users/{user_id}/deletion-preview")
@router.get("/delete/{user_id}/deletion-preview")
async def preview_user_deletion(
user_id: str,
current_user = Depends(get_current_user_dep),

View File

@@ -140,7 +140,7 @@ class AuthTrainingServiceClient(BaseServiceClient):
"""Cancel all active training jobs for a tenant"""
try:
data = {"tenant_id": tenant_id}
return await self.post("jobs/cancel-tenant", data=data)
return await self.post("/tenants/{tenant_id}/training/jobs/cancel", data=data)
except Exception as e:
logger.error("Failed to cancel tenant training jobs",
tenant_id=tenant_id,
@@ -151,7 +151,7 @@ class AuthTrainingServiceClient(BaseServiceClient):
"""Get all active training jobs for a tenant"""
try:
params = {"status": "running,queued,pending", "tenant_id": tenant_id}
result = await self.get("jobs", params=params)
result = await self.get("/tenants/{tenant_id}/training/jobs/active", params=params)
return result.get("jobs", []) if result else []
except Exception as e:
logger.error("Failed to get tenant active jobs",