Phase 7: Replace render_template() with s-expression rendering in all POST/PUT/DELETE routes

Eliminates all render_template() calls from POST/PUT/DELETE handlers across
all 7 services. Moves sexp_components.py into sexp/ packages per service.

- Blog: like toggle, snippets, cache clear, features/sumup/entry panels,
  create/delete market, WYSIWYG editor panel (render_editor_panel)
- Federation: like/unlike/boost/unboost, follow/unfollow, actor card,
  interaction buttons
- Events: ticket widget, checkin, confirm/decline/provisional, tickets
  config, posts CRUD, description edit/save, calendar/slot/ticket_type
  CRUD, payments, buy tickets, day main panel, entry page
- Market: like toggle, cart add response
- Account: newsletter toggle
- Cart: checkout error pages (3 handlers)
- Orders: checkout error page (1 handler)

Remaining render_template() calls are exclusively in GET handlers and
internal services (email templates, fragment endpoints).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 01:15:29 +00:00
parent e65232761b
commit 838ec982eb
64 changed files with 2920 additions and 545 deletions

View File

@@ -8,7 +8,6 @@ from __future__ import annotations
from quart import (
Blueprint,
request,
render_template,
make_response,
redirect,
g,
@@ -48,7 +47,7 @@ def register(url_prefix="/"):
async def account():
from shared.browser.app.utils.htmx import is_htmx_request
from shared.sexp.page import get_template_context
from sexp_components import render_account_page, render_account_oob
from sexp.sexp_components import render_account_page, render_account_oob
if not g.get("user"):
return redirect(login_url("/"))
@@ -90,7 +89,7 @@ def register(url_prefix="/"):
})
from shared.sexp.page import get_template_context
from sexp_components import render_newsletters_page, render_newsletters_oob
from sexp.sexp_components import render_newsletters_page, render_newsletters_oob
ctx = await get_template_context()
if not is_htmx_request():
@@ -125,10 +124,8 @@ def register(url_prefix="/"):
await g.s.flush()
return await render_template(
"_types/auth/_newsletter_toggle.html",
un=un,
)
from sexp.sexp_components import render_newsletter_toggle
return render_newsletter_toggle(un)
# Catch-all for fragment-provided pages — must be last
@account_bp.get("/<slug>/")
@@ -147,7 +144,7 @@ def register(url_prefix="/"):
abort(404)
from shared.sexp.page import get_template_context
from sexp_components import render_fragment_page, render_fragment_oob
from sexp.sexp_components import render_fragment_page, render_fragment_oob
ctx = await get_template_context()
if not is_htmx_request():

View File

@@ -12,7 +12,6 @@ from datetime import datetime, timezone, timedelta
from quart import (
Blueprint,
request,
render_template,
redirect,
url_for,
session as qsession,
@@ -277,7 +276,7 @@ def register(url_prefix="/auth"):
return redirect(redirect_url)
from shared.sexp.page import get_template_context
from sexp_components import render_login_page
from sexp.sexp_components import render_login_page
ctx = await get_template_context()
return await render_login_page(ctx)
@@ -292,28 +291,20 @@ def register(url_prefix="/auth"):
is_valid, email = validate_email(email_input)
if not is_valid:
return (
await render_template(
"auth/login.html",
error="Please enter a valid email address.",
email=email_input,
),
400,
)
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_login_page
ctx = await get_template_context(error="Please enter a valid email address.", email=email_input)
return await render_login_page(ctx), 400
# Per-email rate limit: 5 magic links per 15 minutes
from shared.infrastructure.rate_limit import _check_rate_limit
try:
allowed, _ = await _check_rate_limit(f"magic_email:{email}", 5, 900)
if not allowed:
return (
await render_template(
"auth/check_email.html",
email=email,
email_error=None,
),
200,
)
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_check_email_page
ctx = await get_template_context(email=email, email_error=None)
return await render_check_email_page(ctx), 200
except Exception:
pass # Redis down — allow the request
@@ -333,11 +324,10 @@ def register(url_prefix="/auth"):
"Please try again in a moment."
)
return await render_template(
"auth/check_email.html",
email=email,
email_error=email_error,
)
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_check_email_page
ctx = await get_template_context(email=email, email_error=email_error)
return await render_check_email_page(ctx)
@auth_bp.get("/magic/<token>/")
async def magic(token: str):
@@ -350,20 +340,17 @@ def register(url_prefix="/auth"):
user, error = await validate_magic_link(s, token)
if error:
return (
await render_template("auth/login.html", error=error),
400,
)
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_login_page
ctx = await get_template_context(error=error)
return await render_login_page(ctx), 400
user_id = user.id
except Exception:
return (
await render_template(
"auth/login.html",
error="Could not sign you in right now. Please try again.",
),
502,
)
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_login_page
ctx = await get_template_context(error="Could not sign you in right now. Please try again.")
return await render_login_page(ctx), 502
assert user_id is not None
@@ -693,7 +680,7 @@ def register(url_prefix="/auth"):
async def device_form():
"""Browser form where user enters the code displayed in terminal."""
from shared.sexp.page import get_template_context
from sexp_components import render_device_page
from sexp.sexp_components import render_device_page
code = request.args.get("code", "")
ctx = await get_template_context(code=code)
return await render_device_page(ctx)
@@ -706,22 +693,20 @@ def register(url_prefix="/auth"):
user_code = (form.get("code") or "").strip().replace("-", "").upper()
if not user_code or len(user_code) != 8:
return await render_template(
"auth/device.html",
error="Please enter a valid 8-character code.",
code=form.get("code", ""),
), 400
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_device_page
ctx = await get_template_context(error="Please enter a valid 8-character code.", code=form.get("code", ""))
return await render_device_page(ctx), 400
from shared.infrastructure.auth_redis import get_auth_redis
r = await get_auth_redis()
device_code = await r.get(f"devflow_uc:{user_code}")
if not device_code:
return await render_template(
"auth/device.html",
error="Code not found or expired. Please try again.",
code=form.get("code", ""),
), 400
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_device_page
ctx = await get_template_context(error="Code not found or expired. Please try again.", code=form.get("code", ""))
return await render_device_page(ctx), 400
if isinstance(device_code, bytes):
device_code = device_code.decode()
@@ -735,19 +720,22 @@ def register(url_prefix="/auth"):
# Logged in — approve immediately
ok = await _approve_device(device_code, g.user)
if not ok:
return await render_template(
"auth/device.html",
error="Code expired or already used.",
), 400
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_device_page
ctx = await get_template_context(error="Code expired or already used.")
return await render_device_page(ctx), 400
return await render_template("auth/device_approved.html")
from shared.sexp.page import get_template_context
from sexp.sexp_components import render_device_approved_page
ctx = await get_template_context()
return await render_device_approved_page(ctx)
@auth_bp.get("/device/complete")
@auth_bp.get("/device/complete/")
async def device_complete():
"""Post-login redirect — completes approval after magic link auth."""
from shared.sexp.page import get_template_context
from sexp_components import render_device_page, render_device_approved_page
from sexp.sexp_components import render_device_page, render_device_approved_page
device_code = request.args.get("code", "")