secrets tab, drop commute filter, favicon, robust error reports
1. Admin → Geheimnisse sub-tab lets you edit ANTHROPIC_API_KEY + BERLIN_WOHNEN_USERNAME/PASSWORD at runtime. Migration v7 adds a secrets(key,value,updated_at) table; startup seeds missing keys from env (idempotent). web reads secrets DB-first (env fallback) via llm._api_key(); alert fetches them from web /internal/secrets on each scan, passes them into Scraper(). Rotating creds no longer needs a redeploy. Masked display: 6 leading + 4 trailing chars, "…" in the middle. Blank form fields leave the stored value untouched. 2. Drop the max_morning_commute filter from UI + server + FILTER_KEYS + filter summary (the underlying Maps.calculate_score code stays for potential future re-enable). 3. /static/didi.webp wired as favicon via <link rel="icon"> in base.html. 4. apply.open_page wraps page.goto in try/except so a failed load still produces a "goto.failed" step + screenshot instead of returning an empty forensics blob. networkidle + post-submission sleep are also made best-effort. The error ZIP export already writes screenshot+HTML per step and final_html — with this change every apply run leaves a reconstructable trail even when the listing is already offline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9fbe1ce728
commit
3bb04210c4
12 changed files with 211 additions and 27 deletions
46
web/templates/_admin_secrets.html
Normal file
46
web/templates/_admin_secrets.html
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<h2 class="font-semibold mb-2">Geheimnisse</h2>
|
||||
<p class="text-sm text-slate-600 mb-4">
|
||||
Hier hinterlegte Werte überschreiben die entsprechenden Umgebungsvariablen zur Laufzeit.
|
||||
Leerlassen bedeutet: der gespeicherte Wert bleibt unverändert.
|
||||
</p>
|
||||
|
||||
{% if secret_flash %}
|
||||
<div class="chip chip-ok mb-4">Gespeichert.</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="/actions/secrets" class="space-y-5 max-w-xl"
|
||||
autocomplete="off" data-lpignore="true" data-1p-ignore data-bwignore data-form-type="other">
|
||||
<input type="hidden" name="csrf" value="{{ csrf }}">
|
||||
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">Anthropic API Key</label>
|
||||
<input class="input" type="text" name="ANTHROPIC_API_KEY"
|
||||
placeholder="{{ secrets_masked.ANTHROPIC_API_KEY or 'nicht gesetzt' }}"
|
||||
autocomplete="off" data-lpignore="true" data-1p-ignore data-bwignore>
|
||||
<p class="text-xs text-slate-500 mt-1">Wird für die Bild-URL-Auswahl durch Haiku verwendet.</p>
|
||||
</div>
|
||||
|
||||
<div class="border-t border-soft pt-4">
|
||||
<h3 class="font-semibold text-sm mb-3">inberlinwohnen.de Login</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">Benutzer / E-Mail</label>
|
||||
<input class="input" type="text" name="BERLIN_WOHNEN_USERNAME"
|
||||
placeholder="{{ secrets_masked.BERLIN_WOHNEN_USERNAME or 'nicht gesetzt' }}"
|
||||
autocomplete="off" data-lpignore="true" data-1p-ignore data-bwignore>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">Passwort</label>
|
||||
<input class="input" type="password" name="BERLIN_WOHNEN_PASSWORD"
|
||||
placeholder="{{ secrets_masked.BERLIN_WOHNEN_PASSWORD or 'nicht gesetzt' }}"
|
||||
autocomplete="new-password" data-lpignore="true" data-1p-ignore data-bwignore>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-slate-500 mt-2">
|
||||
Wird vom Scraper beim Login auf inberlinwohnen.de verwendet. Änderungen greifen
|
||||
automatisch beim nächsten Scrape-Zyklus.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary" type="submit">Speichern</button>
|
||||
</form>
|
||||
|
|
@ -26,10 +26,6 @@
|
|||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">min Größe (m²)</label>
|
||||
<input class="input" name="min_size" value="{{ filters.min_size if filters.min_size is not none else '' }}">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">max Anfahrt morgens (min)</label>
|
||||
<input class="input" name="max_morning_commute" value="{{ filters.max_morning_commute if filters.max_morning_commute is not none else '' }}">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">WBS benötigt</label>
|
||||
<select class="input" name="wbs_required">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
{% block content %}
|
||||
<section class="card">
|
||||
<nav class="flex flex-wrap border-b border-soft px-4">
|
||||
{% set sections = [('protokoll','Protokoll'), ('benutzer','Benutzer')] %}
|
||||
{% set sections = [('protokoll','Protokoll'), ('benutzer','Benutzer'), ('geheimnisse','Geheimnisse')] %}
|
||||
{% for key, label in sections %}
|
||||
<a href="/admin/{{ key }}"
|
||||
class="tab {% if section == key %}active{% endif %}">{{ label }}</a>
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
<div class="p-5">
|
||||
{% if section == 'protokoll' %}{% include "_admin_logs.html" %}
|
||||
{% elif section == 'benutzer' %}{% include "_settings_users.html" %}
|
||||
{% elif section == 'geheimnisse' %}{% include "_admin_secrets.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<link rel="icon" type="image/webp" href="/static/didi.webp">
|
||||
<title>{% block title %}wohnungsdidi{% endblock %}</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/htmx.org@2.0.3"></script>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue