from dataclasses import dataclass, field from typing import List, Optional def clean_host(s: str) -> str: """`https://cloud.foo.de/` → `cloud.foo.de`. Akzeptiert die Eingaben unabhängig davon, ob der User Schema/Slash mit eingetippt hat. Verhindert Doppel-Schemas wie `https://https://cloud.foo.de` beim Bauen von URLs. """ s = (s or "").strip() if "://" in s: s = s.split("://", 1)[1] return s.rstrip("/") @dataclass class Account: name: str vorname: str emailadresse: str pleskhost: str keriohost: str nextcloudhost: str kerioemailkennwort: str pleskemailkennwort: str nextcloudgruppe: str = "" nextcloudspeicher: Optional[int] = None # GB; None = unlimitiert nextcloudkennwort: str = "" def __post_init__(self): self.pleskhost = clean_host(self.pleskhost) self.keriohost = clean_host(self.keriohost) self.nextcloudhost = clean_host(self.nextcloudhost) self.emailadresse = (self.emailadresse or "").strip() @property def vollname(self) -> str: return f"{self.vorname} {self.name}".strip() @property def nextcloud_username(self) -> str: return derive_nc_username(self.vorname, self.name) def derive_nc_username(vorname: str, name: str) -> str: """vorname.nachname, lowercase, Umlaute transliteriert, sichere Zeichen.""" s = f"{vorname.strip().lower()}.{name.strip().lower()}" s = (s.replace("ä", "ae").replace("ö", "oe") .replace("ü", "ue").replace("ß", "ss")) out = [] for ch in s: if ch.isalnum() or ch in "._-": out.append(ch) else: out.append("-") return "".join(out).strip("-.") @dataclass class StepResult: service: str status: str # "angelegt" | "übersprungen" | "Fehler" detail: str = "" @dataclass class AccountResult: account: Account steps: List[StepResult] = field(default_factory=list) @property def has_errors(self) -> bool: return any(s.status == "Fehler" for s in self.steps)