"""Jira integration router — link, search, sync, create issues.""" # Import logging import logging # Import Optional from typing from typing import Optional # Import UUID from uuid from uuid import UUID # Import APIRouter, Depends, Query from fastapi from fastapi import APIRouter, Depends, Query # Import Session from sqlalchemy.orm from sqlalchemy.orm import Session # Import get_db from app.database from app.database import get_db # Import get_current_user, require_role from app.dependencies.auth from app.dependencies.auth import get_current_user, require_role # Import UnitOfWork from app.domain.unit_of_work from app.domain.unit_of_work import UnitOfWork # Import JiraLinkEntityType from app.models.jira_link from app.models.jira_link import JiraLinkEntityType # Import User from app.models.user from app.models.user import User # Import from app.schemas.jira_schema from app.schemas.jira_schema import ( JiraIssueResult, JiraLinkCreate, JiraLinkOut, ) # Import audit_service, jira_service from app.services from app.services import audit_service, jira_service # Assign logger = logging.getLogger(__name__) logger = logging.getLogger(__name__) # Assign router = APIRouter(prefix="/jira", tags=["jira"]) router = APIRouter(prefix="/jira", tags=["jira"]) # Apply the @router.get decorator @router.get("/search", response_model=list[JiraIssueResult]) # Define function search_issues def search_issues( # Entry: q q: str = Query(..., min_length=2), # Entry: max_results max_results: int = Query(10, le=50), # Entry: user user: User = Depends(get_current_user), ) -> list[JiraIssueResult]: """Search Jira issues by JQL or free text.""" # Return jira_service.search_jira_issues(q, max_results) return jira_service.search_jira_issues(q, max_results) # Apply the @router.post decorator @router.post("/links", response_model=JiraLinkOut, status_code=201) # Define function create_link def create_link( # Entry: body body: JiraLinkCreate, # Entry: db db: Session = Depends(get_db), # Entry: user user: User = Depends(get_current_user), ) -> JiraLinkOut: """Associate an Aegis entity with a Jira issue.""" # Open context manager with UnitOfWork(db) as uow: # Assign link = jira_service.create_link( link = jira_service.create_link( db, # Keyword argument: entity_type entity_type=body.entity_type, # Keyword argument: entity_id entity_id=body.entity_id, # Keyword argument: jira_issue_key jira_issue_key=body.jira_issue_key, # Keyword argument: sync_direction sync_direction=body.sync_direction, # Keyword argument: created_by created_by=user.id, ) # Call audit_service.log_action() audit_service.log_action( db, # Keyword argument: user_id user_id=user.id, # Keyword argument: action action="JIRA_LINK_CREATED", # Keyword argument: entity_type entity_type="jira_link", # Keyword argument: entity_id entity_id=str(link.id), # Keyword argument: details details={ # Literal argument value "linked_entity_type": body.entity_type.value, # Literal argument value "linked_entity_id": str(body.entity_id), # Literal argument value "jira_issue_key": body.jira_issue_key, }, ) # Call uow.commit() uow.commit() # Reload ORM object attributes from the database db.refresh(link) # Return link return link # Apply the @router.get decorator @router.get("/links", response_model=list[JiraLinkOut]) # Define function list_links def list_links( # Entry: entity_type entity_type: Optional[JiraLinkEntityType] = None, # Entry: entity_id entity_id: Optional[UUID] = None, # Entry: db db: Session = Depends(get_db), # Entry: user user: User = Depends(get_current_user), ) -> list[JiraLinkOut]: """List Jira links, optionally filtered by entity.""" # Return jira_service.list_links( return jira_service.list_links( db, # Keyword argument: entity_type entity_type=entity_type, # Keyword argument: entity_id entity_id=entity_id, ) # Apply the @router.post decorator @router.post("/links/{link_id}/sync") # Define function sync_link def sync_link( # Entry: link_id link_id: UUID, # Entry: db db: Session = Depends(get_db), # Entry: user user: User = Depends(require_role("admin")), ) -> dict: """Force bidirectional sync for a specific Jira link.""" # Open context manager with UnitOfWork(db) as uow: # Assign link = jira_service.get_link_or_raise(db, link_id) link = jira_service.get_link_or_raise(db, link_id) # Call jira_service.sync_jira_to_aegis() jira_service.sync_jira_to_aegis(db, link) # Call uow.commit() uow.commit() # Return {"message": "Sync completed", "jira_status": link.jira_status} return {"message": "Sync completed", "jira_status": link.jira_status} # Apply the @router.delete decorator @router.delete("/links/{link_id}", status_code=204) # Define function delete_link def delete_link( # Entry: link_id link_id: UUID, # Entry: db db: Session = Depends(get_db), # Entry: user user: User = Depends(get_current_user), ) -> None: """Remove a Jira link.""" # Open context manager with UnitOfWork(db) as uow: # Assign link = jira_service.delete_link(db, link_id) link = jira_service.delete_link(db, link_id) # Call audit_service.log_action() audit_service.log_action( db, # Keyword argument: user_id user_id=user.id, # Keyword argument: action action="jira_link_deleted", # Keyword argument: entity_type entity_type="jira_link", # Keyword argument: entity_id entity_id=str(link_id), # Keyword argument: details details={"jira_issue_key": link.jira_issue_key}, ) # Call uow.commit() uow.commit() # Apply the @router.post decorator @router.post("/create-issue") # Define function create_issue_from_entity def create_issue_from_entity( # Entry: entity_type entity_type: JiraLinkEntityType, # Entry: entity_id entity_id: UUID, # Entry: db db: Session = Depends(get_db), # Entry: user user: User = Depends(get_current_user), ) -> dict: """Auto-create a Jira issue from an Aegis entity and link them.""" # Open context manager with UnitOfWork(db) as uow: # Assign result = jira_service.create_issue_and_link( result = jira_service.create_issue_and_link( db, # Keyword argument: entity_type entity_type=entity_type, # Keyword argument: entity_id entity_id=entity_id, # Keyword argument: created_by created_by=user.id, ) # Call uow.commit() uow.commit() # Return result return result