diff --git a/cauldron/server.py b/cauldron/server.py index aa48169..105b46b 100644 --- a/cauldron/server.py +++ b/cauldron/server.py @@ -160,13 +160,25 @@ def create_app() -> Flask: def me(): u = session["user"] connected = db.get_user_mealie_token_blob(u["sub"]) is not None - return jsonify( - { - "user": u, - "mealie_connected": connected, - } + mealie_user = None + if connected: + client = current_user_mealie() + if client: + try: + mealie_user = client.who_am_i() + except Exception: + mealie_user = None + return render_template_string( + ME_TEMPLATE, user=u, connected=connected, mealie_user=mealie_user, css=_PALETTE_CSS ) + @app.get("/me.json") + @require_session + def me_json(): + u = session["user"] + connected = db.get_user_mealie_token_blob(u["sub"]) is not None + return jsonify({"user": u, "mealie_connected": connected}) + # ---------- mealie connect flow -------------------------------------- @app.get("/connect-mealie") @@ -177,6 +189,7 @@ def create_app() -> Flask: CONNECT_TEMPLATE, user=u, mealie_url=cfg.mealie_base_url, + css=_PALETTE_CSS, ) @app.post("/connect-mealie") @@ -234,36 +247,109 @@ def create_app() -> Flask: return app +_PALETTE_CSS = """ +@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;500;600&display=swap'); +* { box-sizing: border-box; } +body { font-family: system-ui, -apple-system, sans-serif; background: #1f2d1f; color: #f0e6cc; max-width: 720px; margin: 0 auto; padding: 3em 1.5em; line-height: 1.65; } +h1, h2 { font-family: 'Cormorant Garamond', Georgia, serif; font-weight: 500; color: #88a87a; margin: 0 0 .2em 0; letter-spacing: 0.01em; } +h1 { font-size: 2.6em; } +h2 { font-size: 1.6em; color: #6b8e5a; margin-top: 1.6em; } +.lede { color: #ddd4ba; font-size: 1.05em; } +a { color: #88a87a; text-decoration: none; border-bottom: 1px dotted #4d5d3a; } +a:hover { color: #ddd4ba; border-bottom-color: #88a87a; } +.panel { background: #2d3a2a; border: 1px solid #3a4a35; padding: 1.2em 1.4em; margin: 1.4em 0; border-radius: 3px; } +.panel-row { display: flex; justify-content: space-between; align-items: baseline; gap: 1em; } +.muted { color: #6b8e5a; font-size: .9em; } +.kv { display: grid; grid-template-columns: max-content 1fr; gap: .4em 1em; margin: .8em 0; } +.kv dt { color: #6b8e5a; font-size: .9em; } +.kv dd { margin: 0; color: #f0e6cc; font-family: ui-monospace, Menlo, monospace; font-size: .92em; word-break: break-all; } +.btn { display: inline-block; padding: .55em 1.3em; background: #6b8e5a; color: #1f2d1f !important; border: none; font-weight: 600; cursor: pointer; font-size: .95em; border-bottom: none; } +.btn:hover { background: #88a87a; color: #1f2d1f !important; } +.btn-secondary { background: transparent; color: #88a87a !important; border: 1px solid #4d5d3a; } +.btn-secondary:hover { background: #2d3a2a; color: #ddd4ba !important; border-color: #88a87a; } +.btn-row { display: flex; gap: .8em; flex-wrap: wrap; align-items: center; } +input[type=text] { width: 100%; padding: .65em; background: #2d3a2a; border: 1px solid #4d5d3a; color: #f0e6cc; font-family: ui-monospace, Menlo, monospace; font-size: .92em; } +input[type=text]:focus { outline: none; border-color: #88a87a; } +ol li, ul li { margin: .4em 0; } +code { background: #1f2d1f; padding: .1em .45em; border: 1px solid #3a4a35; font-family: ui-monospace, Menlo, monospace; font-size: .9em; } +.status-ok { color: #88a87a; } +.status-warn { color: #c9b27c; } +.brand { color: #6b8e5a; font-family: 'Cormorant Garamond', serif; font-size: .95em; letter-spacing: .15em; text-transform: uppercase; margin-bottom: .2em; } +hr { border: none; border-top: 1px solid #3a4a35; margin: 2em 0; } +""" + + +ME_TEMPLATE = """ +
Welcome back.
+ +Connect your Mealie account so cauldron can act on your behalf — your recipes, your meal plan, your shopping list.
+ + {% endif %} +Hi {{ user.name or user.email }}. Cauldron acts on your Mealie account using your own API token. One-time setup, ~30 seconds.
+Hi {{ user.name or user.email }}. Cauldron acts on Mealie using your own API token. One-time, ~30 seconds.
-cauldron, integration genericcauldron, integration genericStored encrypted at rest. Revoke anytime in Mealie's UI; cauldron will detect and re-prompt.
+Stored encrypted at rest with a Fernet key that lives only in cauldron's env. Revoke anytime in Mealie's UI — cauldron will detect and re-prompt.
"""