Add user role
This commit is contained in:
@@ -8,18 +8,20 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from typing import List, Dict, Any
|
||||
import structlog
|
||||
from uuid import UUID
|
||||
from sqlalchemy import select, delete, func
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.services.messaging import publish_tenant_deleted_event
|
||||
from app.schemas.tenants import (
|
||||
BakeryRegistration, TenantResponse, TenantAccessResponse,
|
||||
TenantUpdate, TenantMemberResponse
|
||||
)
|
||||
from app.services.tenant_service import TenantService
|
||||
# Import unified authentication
|
||||
from shared.auth.decorators import (
|
||||
get_current_user_dep,
|
||||
get_current_tenant_id_dep,
|
||||
require_role
|
||||
require_admin_role
|
||||
)
|
||||
|
||||
logger = structlog.get_logger()
|
||||
@@ -163,4 +165,150 @@ async def add_team_member(
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to add team member"
|
||||
)
|
||||
|
||||
@router.delete("/tenants/{tenant_id}")
|
||||
async def delete_tenant_complete(
|
||||
tenant_id: str,
|
||||
current_user = Depends(get_current_user_dep),
|
||||
_admin_check = Depends(require_admin_role),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Delete a tenant completely with all associated data.
|
||||
|
||||
**WARNING: This operation is irreversible!**
|
||||
|
||||
This endpoint:
|
||||
1. Validates tenant exists and user has permissions
|
||||
2. Deletes all tenant memberships
|
||||
3. Deletes tenant subscription data
|
||||
4. Deletes the tenant record
|
||||
5. Publishes deletion event
|
||||
|
||||
Used by admin user deletion process when a tenant has no other admins.
|
||||
"""
|
||||
|
||||
try:
|
||||
tenant_uuid = uuid.UUID(tenant_id)
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Invalid tenant ID format"
|
||||
)
|
||||
|
||||
try:
|
||||
from app.models.tenants import Tenant, TenantMember, Subscription
|
||||
|
||||
# Step 1: Verify tenant exists
|
||||
tenant_query = select(Tenant).where(Tenant.id == tenant_uuid)
|
||||
tenant_result = await db.execute(tenant_query)
|
||||
tenant = tenant_result.scalar_one_or_none()
|
||||
|
||||
if not tenant:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Tenant {tenant_id} not found"
|
||||
)
|
||||
|
||||
deletion_stats = {
|
||||
"tenant_id": tenant_id,
|
||||
"tenant_name": tenant.name,
|
||||
"deleted_at": datetime.utcnow().isoformat(),
|
||||
"memberships_deleted": 0,
|
||||
"subscriptions_deleted": 0,
|
||||
"errors": []
|
||||
}
|
||||
|
||||
# Step 2: Delete all tenant memberships
|
||||
try:
|
||||
membership_count_query = select(func.count(TenantMember.id)).where(
|
||||
TenantMember.tenant_id == tenant_uuid
|
||||
)
|
||||
membership_count_result = await db.execute(membership_count_query)
|
||||
membership_count = membership_count_result.scalar()
|
||||
|
||||
membership_delete_query = delete(TenantMember).where(
|
||||
TenantMember.tenant_id == tenant_uuid
|
||||
)
|
||||
await db.execute(membership_delete_query)
|
||||
deletion_stats["memberships_deleted"] = membership_count
|
||||
|
||||
logger.info("Deleted tenant memberships",
|
||||
tenant_id=tenant_id,
|
||||
count=membership_count)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error deleting memberships: {str(e)}"
|
||||
deletion_stats["errors"].append(error_msg)
|
||||
logger.error(error_msg)
|
||||
|
||||
# Step 3: Delete subscription data
|
||||
try:
|
||||
subscription_count_query = select(func.count(Subscription.id)).where(
|
||||
Subscription.tenant_id == tenant_uuid
|
||||
)
|
||||
subscription_count_result = await db.execute(subscription_count_query)
|
||||
subscription_count = subscription_count_result.scalar()
|
||||
|
||||
subscription_delete_query = delete(Subscription).where(
|
||||
Subscription.tenant_id == tenant_uuid
|
||||
)
|
||||
await db.execute(subscription_delete_query)
|
||||
deletion_stats["subscriptions_deleted"] = subscription_count
|
||||
|
||||
logger.info("Deleted tenant subscriptions",
|
||||
tenant_id=tenant_id,
|
||||
count=subscription_count)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error deleting subscriptions: {str(e)}"
|
||||
deletion_stats["errors"].append(error_msg)
|
||||
logger.error(error_msg)
|
||||
|
||||
# Step 4: Delete the tenant record
|
||||
try:
|
||||
tenant_delete_query = delete(Tenant).where(Tenant.id == tenant_uuid)
|
||||
tenant_result = await db.execute(tenant_delete_query)
|
||||
|
||||
if tenant_result.rowcount == 0:
|
||||
raise Exception("Tenant record was not deleted")
|
||||
|
||||
await db.commit()
|
||||
|
||||
logger.info("Tenant deleted successfully",
|
||||
tenant_id=tenant_id,
|
||||
tenant_name=tenant.name)
|
||||
|
||||
except Exception as e:
|
||||
await db.rollback()
|
||||
error_msg = f"Error deleting tenant record: {str(e)}"
|
||||
deletion_stats["errors"].append(error_msg)
|
||||
logger.error(error_msg)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=error_msg
|
||||
)
|
||||
|
||||
# Step 5: Publish tenant deletion event
|
||||
try:
|
||||
await publish_tenant_deleted_event(tenant_id, deletion_stats)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to publish tenant deletion event", error=str(e))
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Tenant {tenant_id} deleted successfully",
|
||||
"deletion_details": deletion_stats
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("Unexpected error deleting tenant",
|
||||
tenant_id=tenant_id,
|
||||
error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to delete tenant: {str(e)}"
|
||||
)
|
||||
Reference in New Issue
Block a user