* 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>
37 lines
1 KiB
Python
37 lines
1 KiB
Python
"""Abstract provider interface. Concrete providers live next to this file."""
|
|
import asyncio
|
|
import logging
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass
|
|
|
|
from actions import Recorder
|
|
from classes.application_result import ApplicationResult
|
|
from classes.profile import Profile
|
|
|
|
logger = logging.getLogger("flat-apply")
|
|
|
|
|
|
@dataclass
|
|
class ApplyContext:
|
|
"""Per-request state passed into every provider call."""
|
|
profile: Profile
|
|
submit_forms: bool
|
|
recorder: Recorder
|
|
|
|
|
|
class Provider(ABC):
|
|
@property
|
|
@abstractmethod
|
|
def domain(self) -> str:
|
|
...
|
|
|
|
@abstractmethod
|
|
async def apply_for_flat(self, url: str, ctx: ApplyContext) -> ApplicationResult:
|
|
...
|
|
|
|
def test_apply(self, url, profile: Profile | None = None, submit_forms: bool = False):
|
|
rec = Recorder(url)
|
|
ctx = ApplyContext(profile or Profile(), submit_forms=submit_forms, recorder=rec)
|
|
result = asyncio.run(self.apply_for_flat(url, ctx))
|
|
print(repr(result))
|
|
return result, rec.to_json()
|