Add in-app Settings page for secrets; move Gmail creds out of source
- settings.py: JSON-on-volume store with env fallback; secrets never rendered. - /settings page (⚙️ in nav) to set Gmail address + app password + reminder prefs; password fields are write-only (blank keeps existing). - reminders.py reads Gmail creds from Settings instead of a hardcoded password (resolves #2 in code — note the old password is still in git history; rotate it). - mac_notification no longer crashes off-macOS; FLASK_DEBUG gates debug (#7). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
<a href="{{ url_for('net_worth_view') }}">Net Worth</a>
|
||||
<a href="{{ url_for('summary') }}">Spending Report</a>
|
||||
<a href="{{ url_for('suggestions.suggestions_page') }}" class="nav-suggest" title="Suggestions & feedback" aria-label="Suggestions">💡</a>
|
||||
<a href="{{ url_for('settings_view') }}" class="nav-settings" title="Settings" aria-label="Settings">⚙️</a>
|
||||
</div>
|
||||
</nav>
|
||||
<main>
|
||||
|
||||
59
templates/settings.html
Normal file
59
templates/settings.html
Normal file
@@ -0,0 +1,59 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div style="max-width:640px;">
|
||||
<h1>⚙️ Settings</h1>
|
||||
<p style="color:#7A6E68;margin-bottom:1.25rem;">
|
||||
Secrets are stored on the server (in the data volume) and are never shown
|
||||
here once saved. Leave a password field blank to keep the current value.
|
||||
</p>
|
||||
|
||||
{% if saved %}
|
||||
<div class="alert-banner" style="background:#E7F3E9;border-color:#BFE0C5;margin-bottom:1rem;">
|
||||
<span>✓ Settings saved.</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="POST" action="{{ url_for('settings_view') }}">
|
||||
<fieldset style="border:1px solid #EDE8E2;border-radius:10px;padding:1rem 1.25rem;margin-bottom:1.25rem;">
|
||||
<legend style="padding:0 .5rem;font-weight:600;">📧 Email reminders (Gmail)</legend>
|
||||
|
||||
<label style="display:block;margin-bottom:.9rem;">
|
||||
<span style="display:block;font-size:.85rem;color:#7A6E68;margin-bottom:.25rem;">Gmail address</span>
|
||||
<input type="email" name="gmail_address" value="{{ settings.gmail_address }}"
|
||||
placeholder="you@gmail.com" style="width:100%;padding:.55rem;border:1px solid #cfcfd4;border-radius:8px;">
|
||||
</label>
|
||||
|
||||
<label style="display:block;margin-bottom:.9rem;">
|
||||
<span style="display:block;font-size:.85rem;color:#7A6E68;margin-bottom:.25rem;">
|
||||
Gmail app password
|
||||
{% if secrets_status.gmail_app_password %}
|
||||
<strong style="color:#5A9E68;">· set ✓</strong>
|
||||
{% else %}
|
||||
<strong style="color:#C57A6E;">· not set</strong>
|
||||
{% endif %}
|
||||
</span>
|
||||
<input type="password" name="gmail_app_password" autocomplete="new-password"
|
||||
placeholder="{% if secrets_status.gmail_app_password %}•••••••••••• (leave blank to keep){% else %}16-character app password{% endif %}"
|
||||
style="width:100%;padding:.55rem;border:1px solid #cfcfd4;border-radius:8px;">
|
||||
<span style="display:block;font-size:.78rem;color:#B0A89E;margin-top:.25rem;">
|
||||
Not your normal password — create an
|
||||
<a href="https://myaccount.google.com/apppasswords" target="_blank" rel="noopener">app password</a> in your Google account.
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label style="display:block;margin-bottom:.9rem;">
|
||||
<span style="display:block;font-size:.85rem;color:#7A6E68;margin-bottom:.25rem;">Send reminders to (optional)</span>
|
||||
<input type="email" name="reminder_recipient" value="{{ settings.reminder_recipient }}"
|
||||
placeholder="defaults to the Gmail address above" style="width:100%;padding:.55rem;border:1px solid #cfcfd4;border-radius:8px;">
|
||||
</label>
|
||||
|
||||
<label style="display:flex;align-items:center;gap:.5rem;">
|
||||
<input type="checkbox" name="reminders_enabled" {% if settings.reminders_enabled %}checked{% endif %}>
|
||||
<span>Email reminders enabled</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save settings</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user