#!/usr/bin/env python3 """TUI wizard to configure contact details for the laendleimmo.at scraper.""" import json import sys from pathlib import Path try: import questionary from questionary import Style except ImportError: sys.exit("questionary is not installed. Run: pip install questionary") CONFIG_FILE = Path(__file__).parent / "contact_config.json" STYLE = Style( [ ("qmark", "fg:#00aabb bold"), ("question", "bold"), ("answer", "fg:#00aabb bold"), ("pointer", "fg:#00aabb bold"), ("selected", "fg:#00aabb"), ("separator", "fg:#6c6c6c"), ("instruction", "fg:#858585 italic"), ] ) DEFAULT_MESSAGE = """\ Sehr geehrte Damen und Herren, ich interessiere mich sehr für Ihre Immobilie und würde mich über einen \ Besichtigungstermin sehr freuen. Bitte nehmen Sie Kontakt mit mir auf, damit wir einen Termin vereinbaren können. Mit freundlichen Grüßen {name}""" DIVIDER = "─" * 52 def ask(fn, *args, **kwargs): """Wrapper that exits cleanly on Ctrl-C.""" result = fn(*args, style=STYLE, **kwargs).ask() if result is None: print("\nAborted.") sys.exit(0) return result def validate_email(v: str) -> bool | str: return True if "@" in v and "." in v.split("@")[-1] else "Enter a valid e-mail address" def enter_multiline(prompt: str, default: str = "") -> str: print(f"\n {prompt}") print(f" (type your message; enter a blank line to finish)") if default: print(f" Current value shown below — press Enter on blank line to keep it:\n") print(" " + default.replace("\n", "\n ")) print() lines: list[str] = [] try: while True: line = input(" > ") if line == "" and lines and lines[-1] == "": lines.pop() break lines.append(line) except (KeyboardInterrupt, EOFError): print("\nAborted.") sys.exit(0) text = "\n".join(lines).strip() return text if text else default def load_existing() -> dict: if CONFIG_FILE.exists(): with open(CONFIG_FILE, encoding="utf-8") as f: return json.load(f) return {} def show_summary(cfg: dict) -> None: print(f"\n {DIVIDER}") print(" Saved configuration:") print(f" {DIVIDER}") print(f" Name : {cfg.get('name', '')}") print(f" E-mail : {cfg.get('email', '')}") print(f" Phone : {cfg.get('phone') or '(not set)'}") msg_preview = cfg.get("message", "")[:60].replace("\n", " ") print(f" Message : {msg_preview}…") login = cfg.get("login_email", "") print(f" Login : {login if login else '(not configured)'}") print(f" {DIVIDER}") print(f" Config : {CONFIG_FILE}\n") def main() -> None: print() print(f" {DIVIDER}") print(" ländleimmo.at — Contact Configuration Wizard") print(f" {DIVIDER}\n") existing = load_existing() if existing: edit = ask( questionary.confirm, "Existing config found. Edit it?", default=True, ) if not edit: show_summary(existing) return # ── Personal details ────────────────────────────────────────────────── # print(f"\n {DIVIDER}") print(" 1 / 3 Personal details") print(f" {DIVIDER}\n") name = ask( questionary.text, "Full name:", default=existing.get("name", ""), ) email = ask( questionary.text, "E-mail address:", default=existing.get("email", ""), validate=validate_email, ) phone = ask( questionary.text, "Phone number (optional — press Enter to skip):", default=existing.get("phone", ""), ) # ── Message ─────────────────────────────────────────────────────────── # print(f"\n {DIVIDER}") print(" 2 / 3 Contact message") print(f" {DIVIDER}") print(" Tip: use {name} as a placeholder for your name.") use_default_msg = ask( questionary.select, "Message template:", choices=[ questionary.Choice("Use built-in German template", value="default"), questionary.Choice("Write / edit message now", value="custom"), *([questionary.Choice("Keep existing message", value="keep")] if existing.get("message") else []), ], ) if use_default_msg == "default": message = DEFAULT_MESSAGE elif use_default_msg == "keep": message = existing["message"] else: message = enter_multiline( "Your contact message:", default=existing.get("message", DEFAULT_MESSAGE), ) # ── Site login (optional) ────────────────────────────────────────────── # print(f"\n {DIVIDER}") print(" 3 / 3 Site login (optional)") print(f" {DIVIDER}") print(" If you have an account on laendleimmo.at the scraper can log in") print(" first so personal data is pre-filled on the contact form.\n") use_login = ask( questionary.confirm, "Configure site login credentials?", default=bool(existing.get("login_email")), ) login_email = "" login_password = "" if use_login: login_email = ask( questionary.text, "Site login e-mail:", default=existing.get("login_email", email), ) login_password = ask( questionary.password, "Site login password:", ) # ── Build and save ───────────────────────────────────────────────────── # cfg: dict = { "name": name, "email": email, "phone": phone, "message": message, } if use_login: cfg["login_email"] = login_email cfg["login_password"] = login_password CONFIG_FILE.parent.mkdir(parents=True, exist_ok=True) with open(CONFIG_FILE, "w", encoding="utf-8") as f: json.dump(cfg, f, indent=2, ensure_ascii=False) show_summary(cfg) print(" Configuration saved successfully.\n") if __name__ == "__main__": main()