Files
gh-christianlouis-dmarq/backend/app/services/workspace_operator.py
T
2026-05-23 20:10:30 +02:00

190 lines
6.2 KiB
Python

"""Cross-workspace operator summaries for MSP mode."""
# pylint: disable=not-callable
from __future__ import annotations
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional
from sqlalchemy import func
from sqlalchemy.orm import Session
from app.models.alert import AlertHistory
from app.models.domain import Domain
from app.models.mail_source import MailSource
from app.models.mail_source_import import MailSourceImport
from app.models.report import DMARCReport
from app.models.workspace import Workspace
from app.models.workspace_access import WorkspaceAuditLog
def retention_to_dict(workspace: Workspace) -> Dict[str, int]:
"""Return workspace retention controls."""
return {
"aggregate_reports_days": workspace.report_retention_days,
"forensic_reports_days": workspace.forensic_retention_days,
"tls_reports_days": workspace.tls_report_retention_days,
}
def _last_import(db: Session, workspace: Workspace) -> Optional[MailSourceImport]:
return (
db.query(MailSourceImport)
.join(MailSource, MailSourceImport.mail_source_id == MailSource.id)
.filter(MailSource.workspace_id == workspace.id)
.order_by(MailSourceImport.finished_at.desc(), MailSourceImport.id.desc())
.first()
)
def _recent_audit_rows(
db: Session,
workspace: Workspace,
*,
since: datetime,
limit: int = 5,
) -> List[WorkspaceAuditLog]:
return (
db.query(WorkspaceAuditLog)
.filter(
WorkspaceAuditLog.workspace_id == workspace.id,
WorkspaceAuditLog.created_at >= since,
)
.order_by(WorkspaceAuditLog.created_at.desc(), WorkspaceAuditLog.id.desc())
.limit(limit)
.all()
)
def _active_alert_count(db: Session, domain_names: List[str]) -> int:
if not domain_names:
return 0
return (
db.query(func.count(AlertHistory.id))
.filter(AlertHistory.domain.in_(domain_names), AlertHistory.is_active.is_(True))
.scalar()
or 0
)
def _failed_import_count(db: Session, workspace: Workspace, since: datetime) -> int:
return (
db.query(func.count(MailSourceImport.id))
.join(MailSource, MailSourceImport.mail_source_id == MailSource.id)
.filter(
MailSource.workspace_id == workspace.id,
MailSourceImport.finished_at >= since,
MailSourceImport.status != "success",
)
.scalar()
or 0
)
def _health_status(
*,
domain_count: int,
enabled_sources: int,
verified_domains: int,
active_alerts: int,
failed_imports: int,
last_import: Optional[MailSourceImport],
) -> str:
if domain_count == 0 or enabled_sources == 0 or active_alerts > 0 or failed_imports > 0:
return "critical"
if verified_domains < domain_count or last_import is None:
return "warning"
return "healthy"
def workspace_operator_summary( # pylint: disable=too-many-locals
db: Session,
workspace: Workspace,
*,
now: Optional[datetime] = None,
) -> Dict[str, Any]:
"""Return one safe cross-workspace operator summary."""
now = now or datetime.utcnow()
since = now - timedelta(days=7)
domains = (
db.query(Domain).filter(Domain.workspace_id == workspace.id).order_by(Domain.name).all()
)
domain_names = [domain.name for domain in domains]
domain_count = len(domains)
active_domains = sum(1 for domain in domains if domain.active)
verified_domains = sum(1 for domain in domains if domain.verified)
source_count = (
db.query(func.count(MailSource.id)).filter(MailSource.workspace_id == workspace.id).scalar()
or 0
)
enabled_sources = (
db.query(func.count(MailSource.id))
.filter(MailSource.workspace_id == workspace.id, MailSource.enabled.is_(True))
.scalar()
or 0
)
report_count = (
db.query(func.count(DMARCReport.id))
.join(Domain, DMARCReport.domain_id == Domain.id)
.filter(Domain.workspace_id == workspace.id)
.scalar()
or 0
)
last_import = _last_import(db, workspace)
active_alerts = _active_alert_count(db, domain_names)
failed_imports = _failed_import_count(db, workspace, since)
drift_rows = _recent_audit_rows(db, workspace, since=since)
return {
"workspace": {
"id": workspace.id,
"slug": workspace.slug,
"name": workspace.name,
"active": workspace.active,
},
"health": {
"status": _health_status(
domain_count=domain_count,
enabled_sources=int(enabled_sources),
verified_domains=verified_domains,
active_alerts=active_alerts,
failed_imports=failed_imports,
last_import=last_import,
),
"active_alerts": active_alerts,
"failed_imports_7d": failed_imports,
"drift_events_7d": len(drift_rows),
},
"domains": {
"total": domain_count,
"active": active_domains,
"verified": verified_domains,
"names": domain_names,
},
"mail_sources": {
"total": source_count,
"enabled": int(enabled_sources),
"last_import_at": last_import.finished_at.isoformat() if last_import else None,
"last_import_status": last_import.status if last_import else None,
},
"reports": {"aggregate_total": int(report_count)},
"retention": retention_to_dict(workspace),
"recent_drift": [
{
"action": row.action,
"entity_type": row.entity_type,
"entity_name": row.entity_name,
"created_at": row.created_at.isoformat() if row.created_at else None,
}
for row in drift_rows
],
}
def list_workspace_operator_summaries(db: Session) -> List[Dict[str, Any]]:
"""Return safe summaries for every active workspace."""
workspaces = (
db.query(Workspace).filter(Workspace.active.is_(True)).order_by(Workspace.slug).all()
)
return [workspace_operator_summary(db, workspace) for workspace in workspaces]