""" Demo Operations API - Business operations for demo session management """ from fastapi import APIRouter, Depends, HTTPException, Path import structlog import jwt from app.api.schemas import DemoSessionResponse, DemoSessionStats from app.services import DemoSessionManager, DemoCleanupService from app.core import get_db, get_redis, DemoRedisWrapper from sqlalchemy.ext.asyncio import AsyncSession from shared.routing import RouteBuilder router = APIRouter(tags=["demo-operations"]) logger = structlog.get_logger() route_builder = RouteBuilder('demo') @router.post( route_builder.build_resource_action_route("sessions", "session_id", "extend", include_tenant_prefix=False), response_model=DemoSessionResponse ) async def extend_demo_session( session_id: str = Path(...), db: AsyncSession = Depends(get_db), redis: DemoRedisWrapper = Depends(get_redis) ): """Extend demo session expiration (BUSINESS OPERATION)""" try: session_manager = DemoSessionManager(db, redis) session = await session_manager.extend_session(session_id) session_token = jwt.encode( { "session_id": session.session_id, "virtual_tenant_id": str(session.virtual_tenant_id), "demo_account_type": session.demo_account_type, "exp": session.expires_at.timestamp() }, "demo-secret-key", algorithm="HS256" ) return { "session_id": session.session_id, "virtual_tenant_id": str(session.virtual_tenant_id), "demo_account_type": session.demo_account_type, "status": session.status.value, "created_at": session.created_at, "expires_at": session.expires_at, "demo_config": session.session_metadata.get("demo_config", {}), "session_token": session_token } except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error("Failed to extend session", error=str(e)) raise HTTPException(status_code=500, detail=str(e)) @router.get( route_builder.build_base_route("stats", include_tenant_prefix=False), response_model=DemoSessionStats ) async def get_demo_stats( db: AsyncSession = Depends(get_db), redis: DemoRedisWrapper = Depends(get_redis) ): """Get demo session statistics (BUSINESS OPERATION)""" session_manager = DemoSessionManager(db, redis) stats = await session_manager.get_session_stats() return stats @router.post( route_builder.build_operations_route("cleanup", include_tenant_prefix=False), response_model=dict ) async def run_cleanup( db: AsyncSession = Depends(get_db), redis: DemoRedisWrapper = Depends(get_redis) ): """Manually trigger session cleanup (BUSINESS OPERATION - Internal endpoint for CronJob)""" cleanup_service = DemoCleanupService(db, redis) stats = await cleanup_service.cleanup_expired_sessions() return stats @router.post( "/demo/sessions/{session_id}/seed-alerts", response_model=dict ) async def seed_demo_alerts( session_id: str = Path(...), db: AsyncSession = Depends(get_db), redis: DemoRedisWrapper = Depends(get_redis) ): """Seed enriched demo alerts for a demo session (DEMO OPERATION)""" try: import subprocess import os # Get session to validate and get tenant_id session_manager = DemoSessionManager(db, redis) session = await session_manager.get_session(session_id) if not session: raise HTTPException(status_code=404, detail="Demo session not found") # Set environment variables for seeding script env = os.environ.copy() env['DEMO_TENANT_ID'] = str(session.virtual_tenant_id) # Determine script path based on environment # In container: /app/scripts/seed_enriched_alert_demo.py # In development: services/demo_session/scripts/seed_enriched_alert_demo.py script_path = '/app/scripts/seed_enriched_alert_demo.py' if os.path.exists('/app/scripts') else 'services/demo_session/scripts/seed_enriched_alert_demo.py' # Run the seeding script result = subprocess.run( ['python3', script_path], env=env, capture_output=True, text=True, timeout=30 ) if result.returncode != 0: logger.error("Alert seeding failed", stdout=result.stdout, stderr=result.stderr) raise HTTPException(status_code=500, detail=f"Alert seeding failed: {result.stderr}") logger.info("Demo alerts seeded successfully", session_id=session_id) return { "status": "success", "session_id": session_id, "tenant_id": str(session.virtual_tenant_id), "alerts_seeded": 5, "message": "Demo alerts published and will be enriched automatically" } except subprocess.TimeoutExpired: raise HTTPException(status_code=504, detail="Alert seeding timeout") except Exception as e: logger.error("Failed to seed alerts", error=str(e), session_id=session_id) raise HTTPException(status_code=500, detail=str(e))