import json from datetime import datetime from typing import Any, Dict, Iterable, Optional from sqlalchemy.orm import Session from app.models.mail_source import MailSource from app.models.mail_source_import import MailSourceImport MAX_STORED_ERRORS = 10 MAX_ERROR_LENGTH = 500 MAX_STORED_DETAILS = 50 MAX_DETAIL_VALUE_LENGTH = 300 DETAIL_FIELDS = { "status", "reason", "message_id", "filename", "domain", "report_id", "error", } def _sanitize_error(value: object) -> str: """Return a compact, log-safe error string for storage and UI display.""" text = str(value).replace("\r", "").replace("\n", " ").strip() if len(text) > MAX_ERROR_LENGTH: return text[: MAX_ERROR_LENGTH - 3] + "..." return text def _json_list(values: Optional[Iterable[Any]]) -> str: return json.dumps([str(value) for value in values or []]) def _sanitize_detail_value(value: object) -> str: text = _sanitize_error(value) if len(text) > MAX_DETAIL_VALUE_LENGTH: return text[: MAX_DETAIL_VALUE_LENGTH - 3] + "..." return text def _json_details(values: Optional[Iterable[Any]]) -> str: details = [] for value in list(values or [])[:MAX_STORED_DETAILS]: if not isinstance(value, dict): continue entry = {} for key in DETAIL_FIELDS: if key in value and value[key] not in (None, ""): entry[key] = _sanitize_detail_value(value[key]) if entry: details.append(entry) return json.dumps(details) def record_import_attempt( db: Session, source: MailSource, results: Dict[str, Any], *, started_at: datetime, trigger: str, ) -> MailSourceImport: """Persist a sanitized summary of a mail source import attempt.""" result_errors = list(results.get("errors") or []) errors = [_sanitize_error(error) for error in result_errors[:MAX_STORED_ERRORS]] success = bool(results.get("success", False)) status = "success" if success and not errors else "warning" if success else "failed" attempt = MailSourceImport( mail_source_id=source.id, trigger=trigger, status=status, processed=int(results.get("processed", 0) or 0), reports_found=int(results.get("reports_found", 0) or 0), duplicate_reports=int(results.get("duplicate_reports", 0) or 0), error_count=len(result_errors), new_domains=_json_list(results.get("new_domains", [])), errors=json.dumps(errors), details=_json_details(results.get("details", [])), started_at=started_at, finished_at=datetime.utcnow(), ) db.add(attempt) return attempt