jira_api / api /webhook_routes.py
Rudraaaa76's picture
challll
82b7c1e
from fastapi import APIRouter, Header, Request, HTTPException
import logging
from services.supabase_service import supabase_service
from integrations.jira_service import JiraIntegrationService
from typing import Dict, Any
from datetime import datetime
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/webhooks/jira", tags=["Webhooks"])
@router.post("")
async def receive_jira_webhook(
request: Request,
x_atlassian_webhook_identifier: str = Header(None)
):
"""
Receive webhook events from Jira and sync data using the user's stored credentials
"""
try:
payload = await request.json()
logger.info(f"Received Jira webhook: {x_atlassian_webhook_identifier}")
# 1. Extract Jira Account ID from payload
account_id = None
if "user" in payload and "accountId" in payload["user"]:
account_id = payload["user"]["accountId"]
elif "issue" in payload and payload["issue"].get("fields", {}).get("assignee"):
account_id = payload["issue"]["fields"]["assignee"].get("accountId")
elif "issue" in payload and payload["issue"].get("fields", {}).get("reporter"):
account_id = payload["issue"]["fields"]["reporter"].get("accountId")
if not account_id:
logger.warning("Could not identify Jira Account ID from webhook payload")
logger.warning(f"Payload snippet: {str(payload)[:500]}...")
return {"status": "ignored", "reason": "no_account_id_found"}
# 2. Find user credentials in Supabase using Account ID
user_creds = supabase_service.get_user_credentials_by_account_id(account_id)
if not user_creds:
logger.warning(f"No Supabase user found with Jira Account ID: {account_id}")
# This is expected for users who haven't logged in yet with the new auth flow
return {"status": "ignored", "reason": "user_not_linked"}
firebase_id = user_creds.get("firebase_id")
jira_token = user_creds.get("jira_api_token")
jira_url = user_creds.get("jira_server_url")
jira_email = user_creds.get("jira_email")
if not jira_token or not jira_url:
logger.warning(f"User {firebase_id} found but missing Jira credentials")
return {"status": "ignored", "reason": "credentials_missing"}
# 3. Initialize Jira Service with USER'S credentials
try:
jira_service = JiraIntegrationService(
jira_email=jira_email,
jira_api_token=jira_token,
jira_server_url=jira_url
)
logger.info(f"Initialized Jira service for user {jira_email} ({account_id})")
# 4. Fetch all data
full_data = {
"webhook_event": payload,
"synced_at": datetime.utcnow().isoformat(),
"assigned_issues": [],
"projects_data": [], # Renamed to store rich data
"boards": []
}
# A. Fetch Assigned Issues (Just for quick reference)
assigned_issues = jira_service.get_issues_assigned_to_user(account_id)
full_data["assigned_issues"] = [issue.model_dump(mode='json') for issue in assigned_issues]
# B. Fetch All Projects & Their Contents (Spaces)
projects = jira_service.get_projects()
logger.info(f"Found {len(projects)} projects for user. Fetching details...")
for project in projects:
# 1. Fetch All Issues in Project (Limit 50 to avoid timeout for now, can increase)
# We need a method to get issues by project key
try:
project_issues = jira_service.get_issues_by_project(project.project_key, max_results=50)
full_data["projects_data"].append({
"project_info": project.model_dump(mode='json'),
"issues": [issue.model_dump(mode='json') for issue in project_issues]
})
except Exception as e:
logger.error(f"Failed to fetch issues for project {project.project_key}: {str(e)}")
# Add project without issues in worst case
full_data["projects_data"].append({
"project_info": project.model_dump(mode='json'),
"issues": []
})
# C. Fetch All Boards & Sprints
boards = jira_service.get_boards()
enhanced_boards = []
logger.info(f"Found {len(boards)} boards. Fetching sprints...")
for board in boards:
board_data = board.copy()
board_id = board.get('id')
# Check Board Type
board_type = board.get('type')
# A. Scrum Boards: Fetch Sprints
if board_type == 'scrum':
try:
sprints = jira_service.get_sprints(board_id)
board_data['sprints'] = [sprint.model_dump(mode='json') for sprint in sprints]
except Exception as e:
logger.warning(f"Could not fetch sprints for Scrum board {board_id}: {str(e)}")
board_data['sprints'] = []
# B. Kanban Boards: Fetch Configuration (Columns & WIP)
elif board_type == 'kanban':
try:
config = jira_service.get_board_configuration(board_id)
board_data['configuration'] = config.model_dump(mode='json')
except Exception as e:
logger.warning(f"Could not fetch config for Kanban board {board_id}: {str(e)}")
board_data['configuration'] = {}
# C. Unknown/Other
else:
logger.info(f"Skipping detailed fetch for board type '{board_type}' (ID: {board_id})")
enhanced_boards.append(board_data)
full_data["boards"] = enhanced_boards
logger.info(f"Synced for user {account_id}: Assigned={len(assigned_issues)}, Projects={len(full_data['projects_data'])}, Boards={len(enhanced_boards)}")
# 5. Store data
success = supabase_service.upsert_jira_data(firebase_id, full_data)
if success:
return {"status": "processed", "user": firebase_id}
else:
raise HTTPException(status_code=500, detail="Failed to store data")
except Exception as e:
logger.error(f"Error syncing data for user {account_id}: {str(e)}")
# Return 200 to acknowledge webhook but log error
return {"status": "error", "detail": str(e)}
except Exception as e:
logger.error(f"Error processing webhook: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))