68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
import re
|
|
from dataclasses import dataclass, field
|
|
|
|
from ..chat.base import Target
|
|
from ..chat.targets import valid_target
|
|
from ..globs import validate_glob
|
|
from .limits import (AI_HINT_MAX, DEFAULT_MIN_STATE, DELAY_MINUTES_RANGE, MIN_STATE_RANGE, NAME_MAX,
|
|
OUTPUT_CONTAINS_MAX, REMINDER_HOURS_RANGE, TARGET_MAX)
|
|
from .rules import ALL_KINDS
|
|
|
|
BACKENDS = ("telegram", "matrix")
|
|
CONTROL_RE = re.compile(r"[\x00-\x08\x0b-\x1f\x7f]")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RouteInput:
|
|
name: str = ""
|
|
match_host: str = ""
|
|
match_service: str = ""
|
|
min_state: int = DEFAULT_MIN_STATE
|
|
kinds: tuple[str, ...] = ALL_KINDS
|
|
stop_on_match: bool = False
|
|
enabled: bool = True
|
|
targets: tuple[Target, ...] = field(default_factory=tuple)
|
|
delay_minutes: int | None = None
|
|
output_contains: str = ""
|
|
ai_enabled: bool = True
|
|
ai_hint: str = ""
|
|
reminder_hours: int | None = None
|
|
loud: bool = True
|
|
use_default_targets: bool = False
|
|
|
|
|
|
def _range_error(value: int | None, bounds: tuple[int, int], label: str, unit: str = "") -> list[str]:
|
|
low, high = bounds
|
|
if value is not None and not low <= value <= high:
|
|
suffix = f" {unit}" if unit else ""
|
|
return [f"{label} muss zwischen {low} und {high}{suffix} liegen."]
|
|
return []
|
|
|
|
|
|
def validate_route(data: RouteInput) -> list[str]:
|
|
errors = []
|
|
if not data.name.strip():
|
|
errors.append("Name fehlt.")
|
|
elif len(data.name) > NAME_MAX:
|
|
errors.append(f"Name ist zu lang (max. {NAME_MAX} Zeichen).")
|
|
errors += validate_glob(data.match_host, "Host-Muster") + validate_glob(data.match_service, "Service-Muster")
|
|
errors += _range_error(data.min_state, MIN_STATE_RANGE, "Mindest-Schweregrad")
|
|
if not data.kinds or any(kind not in ALL_KINDS for kind in data.kinds):
|
|
errors.append("Mindestens eine gültige Alarmart wählen.")
|
|
errors += _range_error(data.delay_minutes, DELAY_MINUTES_RANGE, "Verzögerung", "Minuten")
|
|
errors += _range_error(data.reminder_hours, REMINDER_HOURS_RANGE, "Erinnerung", "Stunden")
|
|
if len(data.output_contains) > OUTPUT_CONTAINS_MAX:
|
|
errors.append(f"Der Ausgabe-Text ist zu lang (max. {OUTPUT_CONTAINS_MAX} Zeichen).")
|
|
if CONTROL_RE.search(data.output_contains):
|
|
errors.append("Der Ausgabe-Text enthält Steuerzeichen.")
|
|
if len(data.ai_hint) > AI_HINT_MAX:
|
|
errors.append(f"Der KI-Hinweis ist zu lang (max. {AI_HINT_MAX} Zeichen).")
|
|
if CONTROL_RE.search(data.ai_hint):
|
|
errors.append("Der KI-Hinweis enthält Steuerzeichen.")
|
|
for target in data.targets:
|
|
if target.backend not in BACKENDS:
|
|
errors.append(f"Unbekanntes Backend: {target.backend}")
|
|
elif len(target.target) > TARGET_MAX or not valid_target(target.backend, target.target):
|
|
errors.append(f"Ungültiges Ziel für {target.backend}.")
|
|
return errors
|