Improve the frontend and fix TODOs
This commit is contained in:
@@ -5,7 +5,7 @@ Service-to-service endpoint for cloning recipe and production data
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Header
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy import select, delete, func
|
||||
import structlog
|
||||
import uuid
|
||||
from datetime import datetime, timezone, timedelta
|
||||
@@ -375,3 +375,83 @@ async def clone_health_check(_: bool = Depends(verify_internal_api_key)):
|
||||
"clone_endpoint": "available",
|
||||
"version": "2.0.0"
|
||||
}
|
||||
|
||||
|
||||
@router.delete("/tenant/{virtual_tenant_id}")
|
||||
async def delete_demo_data(
|
||||
virtual_tenant_id: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_: bool = Depends(verify_internal_api_key)
|
||||
):
|
||||
"""
|
||||
Delete all recipe data for a virtual demo tenant
|
||||
|
||||
Called by demo session cleanup service to remove ephemeral data
|
||||
when demo sessions expire or are destroyed.
|
||||
"""
|
||||
logger.info(
|
||||
"Deleting recipe data for virtual tenant",
|
||||
virtual_tenant_id=virtual_tenant_id
|
||||
)
|
||||
|
||||
start_time = datetime.now(timezone.utc)
|
||||
|
||||
try:
|
||||
virtual_uuid = uuid.UUID(virtual_tenant_id)
|
||||
|
||||
# Count records before deletion
|
||||
recipe_count = await db.scalar(
|
||||
select(func.count(Recipe.id)).where(Recipe.tenant_id == virtual_uuid)
|
||||
)
|
||||
ingredient_count = await db.scalar(
|
||||
select(func.count(RecipeIngredient.id)).where(RecipeIngredient.tenant_id == virtual_uuid)
|
||||
)
|
||||
|
||||
# Delete in correct order (RecipeIngredient references Recipe)
|
||||
await db.execute(
|
||||
delete(RecipeIngredient).where(RecipeIngredient.tenant_id == virtual_uuid)
|
||||
)
|
||||
await db.execute(
|
||||
delete(Recipe).where(Recipe.tenant_id == virtual_uuid)
|
||||
)
|
||||
|
||||
await db.commit()
|
||||
|
||||
duration_ms = int((datetime.now(timezone.utc) - start_time).total_seconds() * 1000)
|
||||
|
||||
logger.info(
|
||||
"Recipe data deleted successfully",
|
||||
virtual_tenant_id=virtual_tenant_id,
|
||||
recipes_deleted=recipe_count,
|
||||
ingredients_deleted=ingredient_count,
|
||||
duration_ms=duration_ms
|
||||
)
|
||||
|
||||
return {
|
||||
"service": "recipes",
|
||||
"status": "deleted",
|
||||
"virtual_tenant_id": virtual_tenant_id,
|
||||
"records_deleted": {
|
||||
"recipes": recipe_count,
|
||||
"recipe_ingredients": ingredient_count,
|
||||
"total": recipe_count + ingredient_count
|
||||
},
|
||||
"duration_ms": duration_ms
|
||||
}
|
||||
|
||||
except ValueError as e:
|
||||
logger.error("Invalid UUID format", error=str(e))
|
||||
raise HTTPException(status_code=400, detail=f"Invalid UUID: {str(e)}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Failed to delete recipe data",
|
||||
virtual_tenant_id=virtual_tenant_id,
|
||||
error=str(e),
|
||||
exc_info=True
|
||||
)
|
||||
await db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to delete recipe data: {str(e)}"
|
||||
)
|
||||
|
||||
@@ -111,6 +111,34 @@ async def search_recipes(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get(
|
||||
route_builder.build_custom_route(RouteCategory.BASE, ["count"]),
|
||||
response_model=dict
|
||||
)
|
||||
async def count_recipes(
|
||||
tenant_id: UUID,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Get count of recipes for a tenant"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
|
||||
# Use the search method with limit 0 to just get the count
|
||||
recipes = await recipe_service.search_recipes(
|
||||
tenant_id=tenant_id,
|
||||
limit=10000 # High limit to get all
|
||||
)
|
||||
|
||||
count = len(recipes)
|
||||
logger.info(f"Retrieved recipe count for tenant {tenant_id}: {count}")
|
||||
|
||||
return {"count": count}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error counting recipes for tenant {tenant_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get(
|
||||
route_builder.build_custom_route(RouteCategory.BASE, ["{recipe_id}"]),
|
||||
response_model=RecipeResponse
|
||||
@@ -188,34 +216,6 @@ async def update_recipe(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get(
|
||||
route_builder.build_custom_route(RouteCategory.BASE, ["count"]),
|
||||
response_model=dict
|
||||
)
|
||||
async def count_recipes(
|
||||
tenant_id: UUID,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Get count of recipes for a tenant"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
|
||||
# Use the search method with limit 0 to just get the count
|
||||
recipes = await recipe_service.search_recipes(
|
||||
tenant_id=tenant_id,
|
||||
limit=10000 # High limit to get all
|
||||
)
|
||||
|
||||
count = len(recipes)
|
||||
logger.info(f"Retrieved recipe count for tenant {tenant_id}: {count}")
|
||||
|
||||
return {"count": count}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error counting recipes for tenant {tenant_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.delete(
|
||||
route_builder.build_custom_route(RouteCategory.BASE, ["{recipe_id}"])
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user