"""App settings + secret storage (Gmail credentials, reminder prefs, etc.). Stored as JSON on the data volume (DATA_DIR/settings.json) via the atomic storage layer — so it is NEVER committed to source control. Secrets resolve with an environment-variable fallback, so a value can come from the settings page OR from the container's .env. This is what lets us pull the hardcoded Gmail app password out of reminders.py (issue #2): the password lives in settings.json on the volume instead. """ import os from storage import load_json, save_json, DATA_DIR SETTINGS_FILE = os.path.join(DATA_DIR, "settings.json") # Keys holding secrets — their values are never rendered back to the browser. SECRET_KEYS = {"gmail_app_password"} DEFAULTS = { "gmail_address": "", "gmail_app_password": "", "reminder_recipient": "", # blank => send to gmail_address "reminders_enabled": True, } def load_settings(): data = load_json(SETTINGS_FILE, {}) or {} merged = dict(DEFAULTS) merged.update(data) return merged def save_settings(data): save_json(SETTINGS_FILE, data) def get_setting(key, env=None, default=""): """Resolve a setting: stored value first, then env var, then default.""" val = load_settings().get(key) if val not in (None, ""): return val if env: env_val = os.environ.get(env) if env_val not in (None, ""): return env_val return default def is_set(key): """True if a (typically secret) value is present, without revealing it.""" return bool(load_settings().get(key))