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