from fastapi import APIRouter, Depends, HTTPException from loguru import logger import json from typing import Optional, List, Union from sqlalchemy.orm import Session from pydantic import BaseModel, ConfigDict, field_validator from datetime import datetime, timezone # Import timezone import uuid from config import settings from langfuse import Langfuse from database.crud import create_analysis_record from llm.models import JiraWebhookPayload from database.database import get_db_session webhook_router = APIRouter() class BadRequestError(HTTPException): def __init__(self, detail: str): super().__init__(status_code=400, detail=detail) class RateLimitError(HTTPException): def __init__(self, detail: str): super().__init__(status_code=429, detail=detail) class ValidationError(HTTPException): def __init__(self, detail: str): super().__init__(status_code=422, detail=detail) class ValidationError(HTTPException): def __init__(self, detail: str): super().__init__(status_code=422, detail=detail) class JiraWebhookHandler: async def process_jira_request(self, payload: JiraWebhookPayload, db: Session): try: if not payload.issueKey: raise BadRequestError("Missing required field: issueKey") if not payload.summary: raise BadRequestError("Missing required field: summary") # Create new analysis record with initial state new_record = create_analysis_record(db=db, payload=payload) logger.bind( issue_key=payload.issueKey, record_id=new_record.id, timestamp=datetime.now(timezone.utc).isoformat() ).info(f"[{payload.issueKey}] Received webhook and queued for processing.") return {"status": "queued", "record_id": new_record.id} except Exception as e: issue_key = payload.issueKey if payload.issueKey else "N/A" logger.error(f"[{issue_key}] Error receiving webhook: {str(e)}") import traceback logger.error(f"[{issue_key}] Stack trace: {traceback.format_exc()}") raise HTTPException(status_code=500, detail=f"Internal Server Error: {str(e)}") # Initialize handler webhook_handler = JiraWebhookHandler() @webhook_router.post("/api/jira-webhook", status_code=202) async def receive_jira_request(payload: JiraWebhookPayload, db: Session = Depends(get_db_session)): """Jira webhook endpoint - receives and queues requests for processing""" try: result = await webhook_handler.process_jira_request(payload, db) return result except ValidationError as e: raise except BadRequestError as e: raise ValidationError(detail=e.detail) except Exception as e: logger.error(f"Unexpected error in webhook endpoint: {str(e)}") raise HTTPException(status_code=500, detail=f"Internal Server Error: {str(e)}")