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

@@ -209,7 +209,7 @@ async def update_compliance_record(
@router.delete(
route_builder.build_resource_detail_route("food-safety/compliance", "compliance_id"),
status_code=status.HTTP_204_NO_CONTENT
status_code=status.HTTP_403_FORBIDDEN
)
@require_user_role(['admin', 'owner'])
async def delete_compliance_record(
@@ -218,7 +218,33 @@ async def delete_compliance_record(
current_user: dict = Depends(get_current_user_dep),
db: AsyncSession = Depends(get_db)
):
"""Delete (soft delete) compliance record"""
"""
Compliance records CANNOT be deleted for regulatory compliance.
Use the archive endpoint to mark records as inactive.
"""
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail={
"error": "compliance_records_cannot_be_deleted",
"message": "Compliance records cannot be deleted for regulatory compliance. Use PUT /food-safety/compliance/{id}/archive to archive records instead.",
"reason": "Food safety compliance records must be retained for regulatory audits",
"alternative_endpoint": f"/api/v1/tenants/{tenant_id}/inventory/food-safety/compliance/{compliance_id}/archive"
}
)
@router.put(
route_builder.build_nested_resource_route("food-safety/compliance", "compliance_id", "archive"),
response_model=dict
)
@require_user_role(['admin', 'owner'])
async def archive_compliance_record(
compliance_id: UUID = Path(...),
tenant_id: UUID = Path(...),
current_user: dict = Depends(get_current_user_dep),
db: AsyncSession = Depends(get_db)
):
"""Archive (soft delete) compliance record - marks as inactive but retains for audit"""
try:
query = """
UPDATE food_safety_compliance
@@ -228,7 +254,7 @@ async def delete_compliance_record(
result = await db.execute(query, {
"compliance_id": compliance_id,
"tenant_id": tenant_id,
"user_id": UUID(current_user["sub"])
"user_id": UUID(current_user["user_id"])
})
if result.rowcount == 0:
@@ -238,13 +264,38 @@ async def delete_compliance_record(
)
await db.commit()
return None
# Log audit event for archiving compliance record
try:
from shared.security import create_audit_logger, AuditSeverity, AuditAction
audit_logger = create_audit_logger("inventory-service")
await audit_logger.log_event(
db_session=db,
tenant_id=str(tenant_id),
user_id=current_user["user_id"],
action="archive",
resource_type="compliance_record",
resource_id=str(compliance_id),
severity=AuditSeverity.HIGH.value,
description=f"Archived compliance record (retained for regulatory compliance)",
endpoint=f"/food-safety/compliance/{compliance_id}/archive",
method="PUT"
)
except Exception as audit_error:
logger.warning("Failed to log audit event", error=str(audit_error))
return {
"message": "Compliance record archived successfully",
"compliance_id": str(compliance_id),
"archived": True,
"note": "Record retained for regulatory compliance audits"
}
except HTTPException:
raise
except Exception as e:
logger.error("Error deleting compliance record", error=str(e))
logger.error("Error archiving compliance record", error=str(e))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to delete compliance record"
detail="Failed to archive compliance record"
)

View File

@@ -22,12 +22,16 @@ from app.schemas.inventory import (
from shared.auth.decorators import get_current_user_dep
from shared.auth.access_control import require_user_role, admin_role_required, owner_role_required
from shared.routing import RouteBuilder
from shared.security import create_audit_logger, AuditSeverity, AuditAction
# Create route builder for consistent URL structure
route_builder = RouteBuilder('inventory')
router = APIRouter(tags=["ingredients"])
# Initialize audit logger
audit_logger = create_audit_logger("inventory-service")
# Helper function to extract user ID from user object
def get_current_user_id(current_user: dict = Depends(get_current_user_dep)) -> UUID:
"""Extract user ID from current user context"""
@@ -264,6 +268,25 @@ async def hard_delete_ingredient(
try:
service = InventoryService()
deletion_summary = await service.hard_delete_ingredient(ingredient_id, tenant_id)
# Log audit event for hard deletion
try:
await audit_logger.log_deletion(
db_session=db,
tenant_id=str(tenant_id),
user_id=current_user["user_id"],
resource_type="ingredient",
resource_id=str(ingredient_id),
resource_data=deletion_summary,
description=f"Hard deleted ingredient and all associated data",
endpoint=f"/ingredients/{ingredient_id}/hard",
method="DELETE"
)
except Exception as audit_error:
import structlog
logger = structlog.get_logger()
logger.warning("Failed to log audit event", error=str(audit_error))
return deletion_summary
except ValueError as e:
raise HTTPException(