167 lines
5.5 KiB
Python
167 lines
5.5 KiB
Python
# services/recipes/app/api/recipe_quality_configs.py
|
|
"""
|
|
Recipe Quality Configuration API - Atomic CRUD operations on RecipeQualityConfiguration
|
|
"""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Header
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from typing import List
|
|
from uuid import UUID
|
|
import logging
|
|
|
|
from ..core.database import get_db
|
|
from ..services.recipe_service import RecipeService
|
|
from ..schemas.recipes import (
|
|
RecipeQualityConfiguration,
|
|
RecipeQualityConfigurationUpdate
|
|
)
|
|
from shared.routing import RouteBuilder, RouteCategory
|
|
from shared.auth.access_control import require_user_role
|
|
|
|
route_builder = RouteBuilder('recipes')
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter(tags=["recipe-quality-configs"])
|
|
|
|
|
|
def get_user_id(x_user_id: str = Header(...)) -> UUID:
|
|
"""Extract user ID from header"""
|
|
try:
|
|
return UUID(x_user_id)
|
|
except ValueError:
|
|
raise HTTPException(status_code=400, detail="Invalid user ID format")
|
|
|
|
|
|
@router.get(
|
|
route_builder.build_custom_route(RouteCategory.BASE, ["{recipe_id}", "quality-configuration"]),
|
|
response_model=RecipeQualityConfiguration
|
|
)
|
|
async def get_recipe_quality_configuration(
|
|
tenant_id: UUID,
|
|
recipe_id: UUID,
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""Get quality configuration for a specific recipe"""
|
|
try:
|
|
recipe_service = RecipeService(db)
|
|
|
|
recipe = await recipe_service.get_recipe(tenant_id, recipe_id)
|
|
if not recipe:
|
|
raise HTTPException(status_code=404, detail="Recipe not found")
|
|
|
|
quality_config = recipe.get("quality_check_configuration")
|
|
if not quality_config:
|
|
quality_config = {
|
|
"stages": {},
|
|
"overall_quality_threshold": 7.0,
|
|
"critical_stage_blocking": True,
|
|
"auto_create_quality_checks": True,
|
|
"quality_manager_approval_required": False
|
|
}
|
|
|
|
return quality_config
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Error getting recipe quality configuration: {e}")
|
|
raise HTTPException(status_code=500, detail="Internal server error")
|
|
|
|
|
|
@router.put(
|
|
route_builder.build_custom_route(RouteCategory.BASE, ["{recipe_id}", "quality-configuration"]),
|
|
response_model=RecipeQualityConfiguration
|
|
)
|
|
@require_user_role(['admin', 'owner', 'member'])
|
|
async def update_recipe_quality_configuration(
|
|
tenant_id: UUID,
|
|
recipe_id: UUID,
|
|
quality_config: RecipeQualityConfigurationUpdate,
|
|
user_id: UUID = Depends(get_user_id),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""Update quality configuration for a specific recipe"""
|
|
try:
|
|
recipe_service = RecipeService(db)
|
|
|
|
recipe = await recipe_service.get_recipe(tenant_id, recipe_id)
|
|
if not recipe:
|
|
raise HTTPException(status_code=404, detail="Recipe not found")
|
|
|
|
updated_recipe = await recipe_service.update_recipe_quality_configuration(
|
|
tenant_id, recipe_id, quality_config.dict(exclude_unset=True), user_id
|
|
)
|
|
|
|
return updated_recipe["quality_check_configuration"]
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Error updating recipe quality configuration: {e}")
|
|
raise HTTPException(status_code=500, detail="Internal server error")
|
|
|
|
|
|
@router.post(
|
|
route_builder.build_custom_route(RouteCategory.BASE, ["{recipe_id}", "quality-configuration", "stages", "{stage}", "templates"])
|
|
)
|
|
@require_user_role(['admin', 'owner', 'member'])
|
|
async def add_quality_templates_to_stage(
|
|
tenant_id: UUID,
|
|
recipe_id: UUID,
|
|
stage: str,
|
|
template_ids: List[UUID],
|
|
user_id: UUID = Depends(get_user_id),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""Add quality templates to a specific recipe stage"""
|
|
try:
|
|
recipe_service = RecipeService(db)
|
|
|
|
recipe = await recipe_service.get_recipe(tenant_id, recipe_id)
|
|
if not recipe:
|
|
raise HTTPException(status_code=404, detail="Recipe not found")
|
|
|
|
await recipe_service.add_quality_templates_to_stage(
|
|
tenant_id, recipe_id, stage, template_ids, user_id
|
|
)
|
|
|
|
return {"message": f"Added {len(template_ids)} templates to {stage} stage"}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Error adding quality templates to recipe stage: {e}")
|
|
raise HTTPException(status_code=500, detail="Internal server error")
|
|
|
|
|
|
@router.delete(
|
|
route_builder.build_custom_route(RouteCategory.BASE, ["{recipe_id}", "quality-configuration", "stages", "{stage}", "templates", "{template_id}"])
|
|
)
|
|
@require_user_role(['admin', 'owner'])
|
|
async def remove_quality_template_from_stage(
|
|
tenant_id: UUID,
|
|
recipe_id: UUID,
|
|
stage: str,
|
|
template_id: UUID,
|
|
user_id: UUID = Depends(get_user_id),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""Remove a quality template from a specific recipe stage"""
|
|
try:
|
|
recipe_service = RecipeService(db)
|
|
|
|
recipe = await recipe_service.get_recipe(tenant_id, recipe_id)
|
|
if not recipe:
|
|
raise HTTPException(status_code=404, detail="Recipe not found")
|
|
|
|
await recipe_service.remove_quality_template_from_stage(
|
|
tenant_id, recipe_id, stage, template_id, user_id
|
|
)
|
|
|
|
return {"message": f"Removed template from {stage} stage"}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Error removing quality template from recipe stage: {e}")
|
|
raise HTTPException(status_code=500, detail="Internal server error")
|