Add role-based filtering and imporve code

This commit is contained in:
Urtzi Alfaro
2025-10-15 16:12:49 +02:00
parent 96ad5c6692
commit 8f9e9a7edc
158 changed files with 11033 additions and 1544 deletions

View File

@@ -17,7 +17,7 @@ from ..schemas.recipes import (
RecipeStatisticsResponse,
)
from shared.routing import RouteBuilder, RouteCategory
from shared.auth.access_control import require_user_role
from shared.auth.access_control import require_user_role, analytics_tier_required
from shared.auth.decorators import get_current_user_dep
route_builder = RouteBuilder('recipes')
@@ -114,13 +114,18 @@ async def activate_recipe(
route_builder.build_custom_route(RouteCategory.BASE, ["{recipe_id}", "feasibility"]),
response_model=RecipeFeasibilityResponse
)
@analytics_tier_required
async def check_recipe_feasibility(
tenant_id: UUID,
recipe_id: UUID,
batch_multiplier: float = Query(1.0, gt=0),
current_user: dict = Depends(get_current_user_dep),
db: AsyncSession = Depends(get_db)
):
"""Check if recipe can be produced with current inventory"""
"""
Check if recipe can be produced with current inventory (Professional+ tier)
Supports batch scaling for production planning
"""
try:
recipe_service = RecipeService(db)
@@ -187,3 +192,30 @@ async def get_recipe_categories(
except Exception as e:
logger.error(f"Error getting recipe categories: {e}")
raise HTTPException(status_code=500, detail="Internal server error")
@router.get(
route_builder.build_custom_route(RouteCategory.BASE, ["count"])
)
async def get_recipe_count(
tenant_id: UUID,
x_internal_request: str = Header(None),
db: AsyncSession = Depends(get_db)
):
"""
Get total count of recipes for a tenant
Internal endpoint for subscription usage tracking
"""
if x_internal_request != "true":
raise HTTPException(status_code=403, detail="Internal endpoint only")
try:
recipe_service = RecipeService(db)
recipes = await recipe_service.search_recipes(tenant_id, limit=10000)
count = len(recipes)
return {"count": count}
except Exception as e:
logger.error(f"Error getting recipe count: {e}")
raise HTTPException(status_code=500, detail="Internal server error")

View File

@@ -18,9 +18,11 @@ from ..schemas.recipes import (
)
from shared.routing import RouteBuilder, RouteCategory
from shared.auth.access_control import require_user_role
from shared.security import create_audit_logger, AuditSeverity, AuditAction
route_builder = RouteBuilder('recipes')
logger = logging.getLogger(__name__)
audit_logger = create_audit_logger("recipes-service")
router = APIRouter(tags=["recipes"])
@@ -193,9 +195,10 @@ async def update_recipe(
async def delete_recipe(
tenant_id: UUID,
recipe_id: UUID,
user_id: UUID = Depends(get_user_id),
db: AsyncSession = Depends(get_db)
):
"""Delete a recipe"""
"""Delete a recipe (Admin+ only)"""
try:
recipe_service = RecipeService(db)
@@ -206,10 +209,43 @@ async def delete_recipe(
if existing_recipe["tenant_id"] != str(tenant_id):
raise HTTPException(status_code=403, detail="Access denied")
# Capture recipe data before deletion
recipe_data = {
"recipe_name": existing_recipe.get("name"),
"category": existing_recipe.get("category"),
"difficulty_level": existing_recipe.get("difficulty_level"),
"ingredient_count": len(existing_recipe.get("ingredients", []))
}
success = await recipe_service.delete_recipe(recipe_id)
if not success:
raise HTTPException(status_code=404, detail="Recipe not found")
# Log audit event for recipe deletion
try:
# Get sync db for audit logging
from ..core.database import SessionLocal
sync_db = SessionLocal()
try:
await audit_logger.log_deletion(
db_session=sync_db,
tenant_id=str(tenant_id),
user_id=str(user_id),
resource_type="recipe",
resource_id=str(recipe_id),
resource_data=recipe_data,
description=f"Admin deleted recipe {recipe_data['recipe_name']}",
endpoint=f"/recipes/{recipe_id}",
method="DELETE"
)
sync_db.commit()
finally:
sync_db.close()
except Exception as audit_error:
logger.warning(f"Failed to log audit event: {audit_error}")
logger.info(f"Deleted recipe {recipe_id} by user {user_id}")
return {"message": "Recipe deleted successfully"}
except HTTPException: