Files
Aegis/backend/app/services/analytics_service.py
T
kitos c99cc4946a 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-10 13:25:14 +02:00

171 lines
5.4 KiB
Python

"""Analytics service — flat JSON optimized for PowerBI / BI tools."""
# Enable future language features for compatibility
from __future__ import annotations
# Import func from sqlalchemy
from sqlalchemy import func
# Import Session from sqlalchemy.orm
from sqlalchemy.orm import Session
# Import CoverageSnapshot from app.models.coverage_snapshot
from app.models.coverage_snapshot import CoverageSnapshot
# Import Technique from app.models.technique
from app.models.technique import Technique
# Import Test from app.models.test
from app.models.test import Test
# Import User from app.models.user
from app.models.user import User
# Define function get_coverage_analytics
def get_coverage_analytics(db: Session) -> list[dict]:
"""Coverage per technique — flat format for BI dashboards."""
# Assign techniques = db.query(Technique).all()
techniques = db.query(Technique).all()
# Return [
return [
{
# Literal argument value
"mitre_id": t.mitre_id,
# Literal argument value
"name": t.name,
# Literal argument value
"tactic": t.tactic,
# Literal argument value
"status": t.status_global.value if t.status_global else "not_evaluated",
# Literal argument value
"is_subtechnique": t.is_subtechnique,
# Literal argument value
"test_count": len(t.tests) if t.tests else 0,
# Literal argument value
"review_required": t.review_required,
# Literal argument value
"last_review_date": (
t.last_review_date.isoformat() if t.last_review_date else None
),
}
for t in techniques
]
# Define function get_tests_analytics
def get_tests_analytics(
# Entry: db
db: Session,
*,
# Entry: date_from
date_from: str | None = None,
# Entry: date_to
date_to: str | None = None,
) -> list[dict]:
"""All tests with timestamps — flat format for BI dashboards."""
# Assign query = db.query(Test)
query = db.query(Test)
# Check: date_from
if date_from:
# Assign query = query.filter(Test.created_at >= date_from)
query = query.filter(Test.created_at >= date_from)
# Check: date_to
if date_to:
# Assign query = query.filter(Test.created_at <= date_to)
query = query.filter(Test.created_at <= date_to)
# Assign tests = query.all()
tests = query.all()
# Return [
return [
{
# Literal argument value
"id": str(t.id),
# Literal argument value
"technique_id": str(t.technique_id),
# Literal argument value
"name": t.name,
# Literal argument value
"state": t.state.value if t.state else None,
# Literal argument value
"result": t.result.value if t.result else None,
# Literal argument value
"detection_result": (
t.detection_result.value if t.detection_result else None
),
# Literal argument value
"created_at": t.created_at.isoformat() if t.created_at else None,
# Literal argument value
"execution_date": (
t.execution_date.isoformat() if t.execution_date else None
),
# Literal argument value
"platform": t.platform,
# Literal argument value
"tool_used": t.tool_used,
# Literal argument value
"attack_success": t.attack_success,
# Literal argument value
"remediation_status": t.remediation_status,
}
for t in tests
]
# Define function get_trends_analytics
def get_trends_analytics(db: Session) -> list[dict]:
"""Historical coverage snapshots for trend visualization."""
# Assign snapshots = (
snapshots = (
db.query(CoverageSnapshot)
# Chain .order_by() call
.order_by(CoverageSnapshot.created_at)
# Chain .all() call
.all()
)
# Return [
return [
{
# Literal argument value
"date": s.created_at.isoformat() if s.created_at else None,
# Literal argument value
"name": s.name,
# Literal argument value
"total_techniques": s.total_techniques,
# Literal argument value
"validated_count": s.validated_count,
# Literal argument value
"partial_count": s.partial_count,
# Literal argument value
"not_covered_count": s.not_covered_count,
# Literal argument value
"organization_score": s.organization_score,
}
for s in snapshots
]
# Define function get_operators_analytics
def get_operators_analytics(db: Session) -> list[dict]:
"""Per-operator metrics — for workload management dashboards."""
# Assign results = (
results = (
db.query(
User.username,
User.role,
func.count(Test.id).label("test_count"),
)
# Chain .outerjoin() call
.outerjoin(Test, Test.created_by == User.id)
# Chain .group_by() call
.group_by(User.id, User.username, User.role)
# Chain .all() call
.all()
)
# Return [
return [
{"username": r[0], "role": r[1], "test_count": r[2]}
for r in results
]