new-site/scripts/workers/cdr_presets/base.py
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

68 lines
2.3 KiB
Python

"""Switch-preset contract.
A preset tells the portal:
* what human-readable label to show in the dropdown
* which credential fields to render
* what CDR format adapter to hook the output through
* what cron cadence is appropriate by default
And provides two methods to the cdr_puller worker:
* validate(profile) → (ok, detail) — "test connection" button
* fetch(profile, since) → Iterator[(remote_path, bytes)] — pull new files
Credentials on ``profile`` are loaded at the puller layer from the
ERPNext Sensitive ID record linked by ``profile.pull_sensitive_id``.
"""
from __future__ import annotations
import logging
from dataclasses import dataclass
from datetime import datetime
from typing import Iterable, Optional
logger = logging.getLogger(__name__)
@dataclass
class CredentialField:
"""One field the portal should render in the preset credential form."""
key: str # JSON key stored under profile.preset_config / Sensitive ID
label: str # shown on the form
kind: str # 'text' | 'password' | 'ssh_key' | 'select' | 'number'
required: bool = True
sensitive: bool = False # if True, stored encrypted in Sensitive ID not profile_config
help: str = ""
options: Optional[list[str]] = None # for kind='select'
@dataclass
class FetchedFile:
remote_path: str
mtime: datetime
content: bytes
size_bytes: int
class BasePreset:
"""Abstract preset. Subclasses set class attributes + implement methods."""
PRESET_SLUG: str = "" # matches cdr_ingestion_profiles.switch_preset
LABEL: str = "" # shown in the portal dropdown
CDR_FORMAT: str = "generic_csv" # matches cdr_ingestion_profiles.format
TRANSPORT_METHOD: str = "" # 'api' | 'scrape' | 'sftp' | 'ftps'
DEFAULT_CRON: str = "0 2 * * *"
CREDENTIAL_FIELDS: tuple[CredentialField, ...] = ()
def validate(self, profile_config: dict, secrets: dict) -> tuple[bool, str]:
"""Test-connection hook for the portal. Returns (ok, detail)."""
raise NotImplementedError
def fetch(
self,
profile_config: dict,
secrets: dict,
since: Optional[datetime],
) -> Iterable[FetchedFile]:
"""Yield new CDR files since `since`. Puller streams them to MinIO."""
raise NotImplementedError