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:
29
reminders.py
29
reminders.py
@@ -7,26 +7,41 @@ from email.mime.multipart import MIMEMultipart
|
||||
from datetime import date, timedelta
|
||||
import calendar as cal_module
|
||||
from bills import load_bills
|
||||
from settings import get_setting
|
||||
|
||||
EMAIL = "bonna61@gmail.com"
|
||||
APP_PASSWORD = "qowu zcff dbtk kqbs"
|
||||
|
||||
def _gmail():
|
||||
"""Resolve Gmail creds + recipient from Settings (env-var fallback)."""
|
||||
email = get_setting("gmail_address", env="GMAIL_ADDRESS", default="")
|
||||
pw = get_setting("gmail_app_password", env="GMAIL_APP_PASSWORD", default="")
|
||||
recipient = get_setting("reminder_recipient", default="") or email
|
||||
return email, pw, recipient
|
||||
|
||||
|
||||
def send_email(subject, body_html, body_text):
|
||||
email, pw, recipient = _gmail()
|
||||
if not (email and pw):
|
||||
print("Gmail not configured in Settings — skipping email reminder.")
|
||||
return
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["Subject"] = subject
|
||||
msg["From"] = f"Moon Household Budget <{EMAIL}>"
|
||||
msg["To"] = EMAIL
|
||||
msg["From"] = f"Moon Household Budget <{email}>"
|
||||
msg["To"] = recipient
|
||||
msg.attach(MIMEText(body_text, "plain"))
|
||||
msg.attach(MIMEText(body_html, "html"))
|
||||
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
|
||||
server.login(EMAIL, APP_PASSWORD)
|
||||
server.sendmail(EMAIL, EMAIL, msg.as_string())
|
||||
server.login(email, pw)
|
||||
server.sendmail(email, recipient, msg.as_string())
|
||||
|
||||
|
||||
def mac_notification(title, message):
|
||||
# macOS-only; no-op (don't crash) when osascript isn't available, e.g. in
|
||||
# the Linux container.
|
||||
script = f'display notification "{message}" with title "{title}" sound name "Default"'
|
||||
subprocess.run(["osascript", "-e", script])
|
||||
try:
|
||||
subprocess.run(["osascript", "-e", script], check=False)
|
||||
except (FileNotFoundError, OSError):
|
||||
pass
|
||||
|
||||
|
||||
def bills_due_in(days):
|
||||
|
||||
Reference in New Issue
Block a user