Files
Aegis/backend/app/routers/jira.py
T
kitos d2a46feba8 refactor(docs+comments): add Google-style docstrings and inline comments across backend
Task D — Google-style docstrings (Args/Returns) on every public function,
method, and class across all 158 Python files in the backend. Zero ruff D
violations (pydocstyle Google convention).

Task E — Explanatory one-line comment before every code line (~11600 new
comments). ruff check passes clean after isort re-sort.
2026-06-11 11:06:55 +02:00

236 lines
7.1 KiB
Python

"""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