jira_api / api /intelligence_routes.py
Rudraaaa76's picture
Added Login
e4c3be8
from fastapi import APIRouter, HTTPException, Query, Depends
from typing import List, Optional
from datetime import datetime, timedelta, date
from integrations.jira_service import create_jira_service
from services.intelligence_service import intelligence_service
from services.auth_service import get_current_user
from models.auth_models import UserCredentials
from models.intelligence_models import (
DeliveryHealthMetrics,
ProductivityMetrics,
CostEfficiencyMetrics,
TeamCapacityMetrics,
RiskAlert,
InsightRecommendation,
KanbanFlowMetrics,
KanbanColumnAnalysis,
WIPLimitRecommendation
)
import logging
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/intelligence", tags=["Intelligence"])
@router.get("/delivery-health/{project_key}", response_model=DeliveryHealthMetrics)
async def get_delivery_health(
project_key: str,
current_user: UserCredentials = Depends(get_current_user),
board_id: Optional[int] = None,
sprint_id: Optional[int] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get delivery health metrics for a project or sprint"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else None
end_dt = date.fromisoformat(end_date) if end_date else None
# Get sprint if specified
sprint = None
if sprint_id:
issues = jira_service.get_sprint_issues(sprint_id)
if board_id:
sprints = jira_service.get_sprints(board_id)
sprint = next((s for s in sprints if s.sprint_id == sprint_id), None)
else:
# Get all issues for the project
issues = jira_service.get_issues_by_project(
project_key=project_key,
max_results=1000,
start_date=datetime.combine(start_dt, datetime.min.time()) if start_dt else None,
end_date=datetime.combine(end_dt, datetime.max.time()) if end_dt else None
)
return intelligence_service.calculate_delivery_health(
issues=issues,
sprint=sprint,
period_start=start_dt,
period_end=end_dt
)
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error calculating delivery health: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/productivity/{project_key}", response_model=List[ProductivityMetrics])
async def get_productivity_metrics(
project_key: str,
current_user: UserCredentials = Depends(get_current_user),
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get productivity metrics for all team members in a project"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=14))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get data
issues = jira_service.get_issues_by_project(
project_key=project_key,
max_results=1000,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
worklogs = jira_service.get_worklogs(
project_key=project_key,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
team_members = jira_service.get_team_members(project_key)
# Calculate metrics for each team member
metrics = []
for member in team_members:
metric = intelligence_service.calculate_productivity_metrics(
issues=issues,
worklogs=worklogs,
team_member_id=member.account_id,
team_member_name=member.display_name,
period_start=start_dt,
period_end=end_dt
)
metrics.append(metric)
return metrics
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error calculating productivity metrics: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/cost-efficiency/{project_key}", response_model=CostEfficiencyMetrics)
async def get_cost_efficiency(
project_key: str,
current_user: UserCredentials = Depends(get_current_user),
start_date: Optional[str] = None,
end_date: Optional[str] = None,
avg_hourly_rate: float = Query(75.0, gt=0)
):
"""Get cost efficiency metrics for a project"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=14))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get data
issues = jira_service.get_issues_by_project(
project_key=project_key,
max_results=1000,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
worklogs = jira_service.get_worklogs(
project_key=project_key,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
return intelligence_service.calculate_cost_efficiency(
issues=issues,
worklogs=worklogs,
period_start=start_dt,
period_end=end_dt,
avg_hourly_rate=avg_hourly_rate
)
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error calculating cost efficiency: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/risk-alerts/{project_key}", response_model=List[RiskAlert])
async def get_risk_alerts(
project_key: str,
current_user: UserCredentials = Depends(get_current_user),
board_id: Optional[int] = None,
sprint_id: Optional[int] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get risk alerts for a project"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=14))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get all metrics
sprint = None
if sprint_id and board_id:
issues = jira_service.get_sprint_issues(sprint_id)
sprints = jira_service.get_sprints(board_id)
sprint = next((s for s in sprints if s.sprint_id == sprint_id), None)
else:
issues = jira_service.get_issues_by_project(
project_key=project_key,
max_results=1000,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
worklogs = jira_service.get_worklogs(
project_key=project_key,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
team_members = jira_service.get_team_members(project_key)
# Calculate metrics
delivery_health = intelligence_service.calculate_delivery_health(
issues=issues,
sprint=sprint,
period_start=start_dt,
period_end=end_dt
)
productivity_metrics = [
intelligence_service.calculate_productivity_metrics(
issues=issues,
worklogs=worklogs,
team_member_id=member.account_id,
team_member_name=member.display_name,
period_start=start_dt,
period_end=end_dt
)
for member in team_members
]
cost_metrics = intelligence_service.calculate_cost_efficiency(
issues=issues,
worklogs=worklogs,
period_start=start_dt,
period_end=end_dt
)
# Generate alerts
return intelligence_service.generate_risk_alerts(
delivery_health=delivery_health,
productivity_metrics=productivity_metrics,
cost_metrics=cost_metrics
)
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error generating risk alerts: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/insights/{project_key}", response_model=List[InsightRecommendation])
async def get_insights(
project_key: str,
current_user: UserCredentials = Depends(get_current_user),
board_id: Optional[int] = None,
sprint_id: Optional[int] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get AI-generated insights and recommendations"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=14))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get all metrics (same as risk alerts)
sprint = None
if sprint_id and board_id:
issues = jira_service.get_sprint_issues(sprint_id)
sprints = jira_service.get_sprints(board_id)
sprint = next((s for s in sprints if s.sprint_id == sprint_id), None)
else:
issues = jira_service.get_issues_by_project(
project_key=project_key,
max_results=1000,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
worklogs = jira_service.get_worklogs(
project_key=project_key,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
team_members = jira_service.get_team_members(project_key)
# Calculate metrics
delivery_health = intelligence_service.calculate_delivery_health(
issues=issues,
sprint=sprint,
period_start=start_dt,
period_end=end_dt
)
productivity_metrics = [
intelligence_service.calculate_productivity_metrics(
issues=issues,
worklogs=worklogs,
team_member_id=member.account_id,
team_member_name=member.display_name,
period_start=start_dt,
period_end=end_dt
)
for member in team_members
]
cost_metrics = intelligence_service.calculate_cost_efficiency(
issues=issues,
worklogs=worklogs,
period_start=start_dt,
period_end=end_dt
)
# Generate insights
return intelligence_service.generate_insights(
delivery_health=delivery_health,
productivity_metrics=productivity_metrics,
cost_metrics=cost_metrics
)
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error generating insights: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/dashboard/{project_key}")
async def get_dashboard_data(
project_key: str,
current_user: UserCredentials = Depends(get_current_user),
board_id: Optional[int] = None,
sprint_id: Optional[int] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get comprehensive dashboard data including all metrics"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=14))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get all data
sprint = None
if sprint_id and board_id:
issues = jira_service.get_sprint_issues(sprint_id)
sprints = jira_service.get_sprints(board_id)
sprint = next((s for s in sprints if s.sprint_id == sprint_id), None)
else:
issues = jira_service.get_issues_by_project(
project_key=project_key,
max_results=1000,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
worklogs = jira_service.get_worklogs(
project_key=project_key,
start_date=datetime.combine(start_dt, datetime.min.time()),
end_date=datetime.combine(end_dt, datetime.max.time())
)
team_members = jira_service.get_team_members(project_key)
# Calculate all metrics
delivery_health = intelligence_service.calculate_delivery_health(
issues=issues,
sprint=sprint,
period_start=start_dt,
period_end=end_dt
)
productivity_metrics = [
intelligence_service.calculate_productivity_metrics(
issues=issues,
worklogs=worklogs,
team_member_id=member.account_id,
team_member_name=member.display_name,
period_start=start_dt,
period_end=end_dt
)
for member in team_members
]
cost_metrics = intelligence_service.calculate_cost_efficiency(
issues=issues,
worklogs=worklogs,
period_start=start_dt,
period_end=end_dt
)
risk_alerts = intelligence_service.generate_risk_alerts(
delivery_health=delivery_health,
productivity_metrics=productivity_metrics,
cost_metrics=cost_metrics
)
insights = intelligence_service.generate_insights(
delivery_health=delivery_health,
productivity_metrics=productivity_metrics,
cost_metrics=cost_metrics
)
return {
"delivery_health": delivery_health,
"productivity_metrics": productivity_metrics,
"cost_efficiency": cost_metrics,
"risk_alerts": risk_alerts,
"insights": insights,
"period": {
"start": start_dt,
"end": end_dt
}
}
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error generating dashboard data: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
# ===== KANBAN INTELLIGENCE ENDPOINTS =====
@router.get("/kanban/flow-metrics/{board_id}", response_model=KanbanFlowMetrics)
async def get_kanban_flow_metrics(
board_id: int,
current_user: UserCredentials = Depends(get_current_user),
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get Kanban flow efficiency metrics for a board"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=30))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get board info
board = jira_service.get_kanban_board_by_id(board_id)
if not board:
raise HTTPException(status_code=404, detail=f"Kanban board {board_id} not found")
# Get issues and columns
columns = jira_service.get_kanban_issues_by_column(board_id)
# Get all issues for the board
all_issues = []
for col in columns:
all_issues.extend(col.issues)
return intelligence_service.calculate_kanban_flow_metrics(
board_id=board_id,
board_name=board.board_name,
issues=all_issues,
columns=columns,
period_start=start_dt,
period_end=end_dt
)
except HTTPException:
raise
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error calculating Kanban flow metrics: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/kanban/column-analysis/{board_id}", response_model=List[KanbanColumnAnalysis])
async def get_kanban_column_analysis(
board_id: int,
current_user: UserCredentials = Depends(get_current_user)
):
"""Get detailed analysis of each Kanban column"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Get board info
board = jira_service.get_kanban_board_by_id(board_id)
if not board:
raise HTTPException(status_code=404, detail=f"Kanban board {board_id} not found")
# Get issues by column
columns = jira_service.get_kanban_issues_by_column(board_id)
# Get all issues
all_issues = []
for col in columns:
all_issues.extend(col.issues)
return intelligence_service.analyze_kanban_columns(
columns=columns,
issues=all_issues
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error analyzing Kanban columns: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/kanban/wip-recommendations/{board_id}", response_model=List[WIPLimitRecommendation])
async def get_wip_recommendations(
board_id: int,
current_user: UserCredentials = Depends(get_current_user),
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get WIP limit recommendations for Kanban board columns"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=30))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get board info
board = jira_service.get_kanban_board_by_id(board_id)
if not board:
raise HTTPException(status_code=404, detail=f"Kanban board {board_id} not found")
# Get columns and issues
columns = jira_service.get_kanban_issues_by_column(board_id)
all_issues = []
for col in columns:
all_issues.extend(col.issues)
# Analyze columns
column_analyses = intelligence_service.analyze_kanban_columns(
columns=columns,
issues=all_issues
)
# Calculate flow metrics
flow_metrics = intelligence_service.calculate_kanban_flow_metrics(
board_id=board_id,
board_name=board.board_name,
issues=all_issues,
columns=columns,
period_start=start_dt,
period_end=end_dt
)
# Generate recommendations
return intelligence_service.generate_wip_recommendations(
column_analyses=column_analyses,
flow_metrics=flow_metrics
)
except HTTPException:
raise
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error generating WIP recommendations: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/kanban/insights/{board_id}", response_model=List[InsightRecommendation])
async def get_kanban_insights(
board_id: int,
current_user: UserCredentials = Depends(get_current_user),
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get AI-generated insights for Kanban board"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=30))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get board info
board = jira_service.get_kanban_board_by_id(board_id)
if not board:
raise HTTPException(status_code=404, detail=f"Kanban board {board_id} not found")
# Get columns and issues
columns = jira_service.get_kanban_issues_by_column(board_id)
all_issues = []
for col in columns:
all_issues.extend(col.issues)
# Calculate all metrics
flow_metrics = intelligence_service.calculate_kanban_flow_metrics(
board_id=board_id,
board_name=board.board_name,
issues=all_issues,
columns=columns,
period_start=start_dt,
period_end=end_dt
)
column_analyses = intelligence_service.analyze_kanban_columns(
columns=columns,
issues=all_issues
)
wip_recommendations = intelligence_service.generate_wip_recommendations(
column_analyses=column_analyses,
flow_metrics=flow_metrics
)
# Generate insights
return intelligence_service.generate_kanban_insights(
flow_metrics=flow_metrics,
column_analyses=column_analyses,
wip_recommendations=wip_recommendations
)
except HTTPException:
raise
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error generating Kanban insights: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/kanban/dashboard/{board_id}")
async def get_kanban_dashboard(
board_id: int,
current_user: UserCredentials = Depends(get_current_user),
start_date: Optional[str] = None,
end_date: Optional[str] = None
):
"""Get comprehensive Kanban dashboard data"""
try:
# Create user-specific Jira service
jira_service = create_jira_service(
current_user.jira_email,
current_user.jira_api_token,
current_user.jira_server_url
)
# Parse dates
start_dt = date.fromisoformat(start_date) if start_date else (date.today() - timedelta(days=30))
end_dt = date.fromisoformat(end_date) if end_date else date.today()
# Get board info
board = jira_service.get_kanban_board_by_id(board_id)
if not board:
raise HTTPException(status_code=404, detail=f"Kanban board {board_id} not found")
# Get columns and issues
columns = jira_service.get_kanban_issues_by_column(board_id)
all_issues = []
for col in columns:
all_issues.extend(col.issues)
# Calculate all metrics
flow_metrics = intelligence_service.calculate_kanban_flow_metrics(
board_id=board_id,
board_name=board.board_name,
issues=all_issues,
columns=columns,
period_start=start_dt,
period_end=end_dt
)
column_analyses = intelligence_service.analyze_kanban_columns(
columns=columns,
issues=all_issues
)
wip_recommendations = intelligence_service.generate_wip_recommendations(
column_analyses=column_analyses,
flow_metrics=flow_metrics
)
insights = intelligence_service.generate_kanban_insights(
flow_metrics=flow_metrics,
column_analyses=column_analyses,
wip_recommendations=wip_recommendations
)
return {
"board": {
"id": board.board_id,
"name": board.board_name,
"type": board.board_type,
"project_key": board.project_key
},
"flow_metrics": flow_metrics,
"column_analyses": column_analyses,
"wip_recommendations": wip_recommendations,
"insights": insights,
"columns_with_issues": columns,
"period": {
"start": start_dt,
"end": end_dt
}
}
except HTTPException:
raise
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid date format: {str(e)}")
except Exception as e:
logger.error(f"Error generating Kanban dashboard: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))