* DB: users + user_profiles/filters/notifications/preferences; applications gets user_id + forensics_json + profile_snapshot_json; new errors table with 14d retention; schema versioning via MIGRATIONS list * auth: password hashes in DB (argon2); env vars seed first admin; per-user sessions; CSRF bound to user id * apply: personal info/WBS moved out of env into the request body; providers take an ApplyContext with Profile + submit_forms; full Playwright recorder (step log, console, page errors, network, screenshots, final HTML) * web: five top-level tabs (Wohnungen/Bewerbungen/Logs/Fehler/Einstellungen); settings sub-tabs profil/filter/benachrichtigungen/account/benutzer; per-user matching, auto-apply and notifications (UI/Telegram/SMTP); red auto-apply switch on Wohnungen tab; forensics detail view for bewerbungen and fehler; retention background thread Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
1.9 KiB
Python
66 lines
1.9 KiB
Python
"""Applicant profile passed from web → apply on each request."""
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
|
|
|
|
@dataclass
|
|
class Profile:
|
|
salutation: str = "Herr"
|
|
firstname: str = ""
|
|
lastname: str = ""
|
|
email: str = ""
|
|
telephone: str = ""
|
|
street: str = ""
|
|
house_number: str = ""
|
|
postcode: str = ""
|
|
city: str = ""
|
|
|
|
# WBS
|
|
is_possessing_wbs: bool = False
|
|
wbs_type: str = "0"
|
|
wbs_valid_till: str = "1970-01-01" # ISO date string
|
|
wbs_rooms: int = 0
|
|
wbs_adults: int = 0
|
|
wbs_children: int = 0
|
|
is_prio_wbs: bool = False
|
|
|
|
# optional: immomio login for providers that need it
|
|
immomio_email: str = ""
|
|
immomio_password: str = ""
|
|
|
|
@property
|
|
def person_count(self) -> int:
|
|
return self.wbs_adults + self.wbs_children
|
|
|
|
@property
|
|
def adult_count(self) -> int:
|
|
return self.wbs_adults
|
|
|
|
@property
|
|
def children_count(self) -> int:
|
|
return self.wbs_children
|
|
|
|
def wbs_valid_till_dt(self) -> datetime:
|
|
try:
|
|
return datetime.strptime(self.wbs_valid_till, "%Y-%m-%d")
|
|
except ValueError:
|
|
return datetime(1970, 1, 1)
|
|
|
|
@classmethod
|
|
def from_dict(cls, d: dict) -> "Profile":
|
|
safe = {k: d.get(k) for k in cls.__dataclass_fields__.keys() if k in d and d[k] is not None}
|
|
# normalise booleans + ints
|
|
for k in ("is_possessing_wbs", "is_prio_wbs"):
|
|
if k in safe:
|
|
v = safe[k]
|
|
if isinstance(v, str):
|
|
safe[k] = v.lower() in ("true", "1", "yes", "on")
|
|
else:
|
|
safe[k] = bool(v)
|
|
for k in ("wbs_rooms", "wbs_adults", "wbs_children"):
|
|
if k in safe:
|
|
try:
|
|
safe[k] = int(safe[k])
|
|
except (TypeError, ValueError):
|
|
safe[k] = 0
|
|
return cls(**safe)
|